diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 4f2ac36a..12a96827 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -12,7 +12,7 @@ Metrics/AbcSize: # Offense count: 2 # Configuration parameters: CountComments. Metrics/ClassLength: - Max: 202 + Max: 212 # Offense count: 3 Metrics/CyclomaticComplexity: diff --git a/README.md b/README.md index e69c1675..f6c5598e 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ This gem adds Entity support to API frameworks, such as [Grape](https://github.c module API module Entities class Status < Grape::Entity + meta description: "My Status" format_with(:iso_timestamp) { |dt| dt.iso8601 } expose :user_name @@ -58,6 +59,16 @@ Entities are a reusable means for converting Ruby objects to API responses. Enti Entities inherit from Grape::Entity, and define a simple DSL. Exposures can use runtime options to determine which fields should be visible, these options are available to `:if`, `:unless`, and `:proc`. +#### Metadata + +Entities may store custom metadata for documentation purposes. + +```ruby +class MyEntity < Grape::Entity + meta custom: "data", other: "value" +end +``` + #### Basic Exposure Define a list of fields that will always be exposed. diff --git a/lib/grape_entity/entity.rb b/lib/grape_entity/entity.rb index 90b4fbc0..87b41a30 100644 --- a/lib/grape_entity/entity.rb +++ b/lib/grape_entity/entity.rb @@ -112,13 +112,16 @@ def formatters end attr_writer :formatters + attr_writer :meta end @formatters = {} + @meta = {} def self.inherited(subclass) subclass.root_exposure = root_exposure.dup subclass.formatters = formatters.dup + subclass.meta = meta.dup end # This method is the primary means by which you will declare what attributes @@ -273,6 +276,26 @@ def self.format_with(name, &block) formatters[name.to_sym] = block end + # This allows you to declare meta data on the entity level, which can be useful for + # automated documentation. + # + # @param pairs [Hash] the name-value pairs to associate + # + # @example Meta declaration + # + # module API + # module Entities + # class User < Grape::Entity + # meta description: "My user entity" + # end + # end + # end + # + def self.meta(pairs = nil) + @meta.update(pairs) if pairs.is_a?(Hash) + @meta + end + # This allows you to set a root element name for your representation. # # @param plural [String] the root key to use when representing @@ -449,6 +472,10 @@ def formatters self.class.formatters end + def meta + self.class.meta + end + # The serializable hash is the Entity's primary output. It is the transformed # hash for the given data model and is used as the basis for serialization to # JSON and other formats. diff --git a/spec/grape_entity/entity_spec.rb b/spec/grape_entity/entity_spec.rb index 08457744..5023f2cb 100644 --- a/spec/grape_entity/entity_spec.rb +++ b/spec/grape_entity/entity_spec.rb @@ -274,6 +274,21 @@ class Parent < Person end end + context 'declare meta' do + it 'sets meta data' do + subject.meta description: 'My favourite entity' + + expect(subject.meta).to include(description: 'My favourite entity') + end + + it 'inherits meta from ancestors' do + subject.meta final: true + child_class = Class.new(subject) + + expect(child_class.meta).to eq subject.meta + end + end + context 'register formatters' do let(:date_formatter) { ->(date) { date.strftime('%m/%d/%Y') } }