diff --git a/README.md b/README.md index 42e2cb26..c559cf07 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,20 @@ end song.to_json #=> {"name":"Fallout","track":1} ``` +You can also a naming strategy at a Representer-level: + +```ruby +module SongRepresenter + include Representable::JSON + + self.naming_strategy = ->(name) { name.camelize } # (with ActiveSupport available) + + property :song_title + property :song_track, as: :track +end + +song.to_json #=> {"songTitle":"Fallout","track":1} +``` ## Wrapping diff --git a/lib/representable/declarative.rb b/lib/representable/declarative.rb index 77246568..4abe73d6 100644 --- a/lib/representable/declarative.rb +++ b/lib/representable/declarative.rb @@ -1,5 +1,12 @@ module Representable module Declarative + def naming_strategy=(strategy) + raise 'The :naming_strategy option should respond to #call?' \ + unless strategy.respond_to?(:call) + + @naming_strategy = strategy + end + def representable_attrs @representable_attrs ||= build_config end @@ -33,6 +40,8 @@ def nested(name, options={}, &block) end def property(name, options={}, &block) + options = { as: naming_strategy.(name.to_s) }.merge(options) if naming_strategy + representable_attrs.add(name, options) do |default_options| # handles :inherit. build_definition(name, default_options, &block) end @@ -49,6 +58,8 @@ def build_inline(base, features, name, options, &block) # DISCUSS: separate modu end private + attr_reader :naming_strategy + # This method is meant to be overridden if you want to add or change DSL options. # The options hash is already initialized, add or change elements as you need. # @@ -83,4 +94,4 @@ def build_config Config.new end end # Declarations -end \ No newline at end of file +end diff --git a/test/as_strategy_test.rb b/test/as_strategy_test.rb new file mode 100644 index 00000000..9b30fead --- /dev/null +++ b/test/as_strategy_test.rb @@ -0,0 +1,64 @@ +require 'test_helper' + +class AsStrategyTest < BaseTest + let(:format) { :hash } + let(:song) { representer.prepare(Struct.new(:title).new('Revolution')) } + + class ReverseNamingStrategy + def call(name) + name.reverse + end + end + + describe 'module' do + describe 'with lambda' do + let(:output) { { 'TITLE' => 'Revolution' } } + let(:input) { { 'TITLE' => 'Wie es geht' } } + + representer! do + self.naming_strategy = ->(name) { name.upcase } + property :title + end + + it { render(song).must_equal_document(output) } + it { parse(song, input).title.must_equal('Wie es geht') } + end + + describe 'with class responding to #call?' do + let(:output) { { 'eltit' => 'Revolution' } } + let(:input) { { 'eltit' => 'Wie es geht' } } + + representer! do + self.naming_strategy = ReverseNamingStrategy.new + property :title + end + + it { render(song).must_equal_document(output) } + it { parse(song, input).title.must_equal('Wie es geht') } + end + + describe 'with class not responding to #call?' do + representer! do + self.naming_strategy = Object.new + property :title + end + + it { -> { render(song) }.must_raise(RuntimeError) } + end + end + + describe 'decorator' do + describe 'with a lambda' do + let(:output) { { 'TITLE' => 'Revolution' } } + let(:input) { { 'TITLE' => 'Wie es geht' } } + + representer!(decorator: true) do + self.naming_strategy = ->(name) { name.upcase } + property :title + end + + it { render(song).must_equal_document(output) } + it { parse(song, input).title.must_equal('Wie es geht') } + end + end +end diff --git a/test/as_test.rb b/test/as_test.rb index d8f4004d..fd05be90 100644 --- a/test/as_test.rb +++ b/test/as_test.rb @@ -20,6 +20,16 @@ class AsTest < MiniTest::Spec it { parse(song, input).name.must_equal "Wie Es Geht" } end + describe "as: with :symbol, overriding naming_strategy default" do + representer!(module: mod) do + self.naming_strategy = ->(name) { name.upcase } + + property :name, as: :title + end + + it { render(song).must_equal_document output } + it { parse(song, input).name.must_equal 'Wie Es Geht' } + end describe "as: with lambda" do representer!(:module => mod) do @@ -40,4 +50,4 @@ class AsTest < MiniTest::Spec it { parse(song, {"[{:volume=>1}]" => "Wie Es Geht"}, :volume => 1).name.must_equal "Wie Es Geht" } end end -end \ No newline at end of file +end