diff options
author | Les Hill and Paul Elliott <dev+leshill+paulelliott@hashrocket.com> | 2010-07-30 05:30:47 +0800 |
---|---|---|
committer | Michael Bleigh <michael@intridea.com> | 2010-08-10 22:57:12 +0800 |
commit | 54b03e8aca856a924b718e826d6bffec4c54148e (patch) | |
tree | b5b118324bf8e6cd1ebc79b88be703b3efdea96a | |
parent | 4beb2bd9c4fd552423b205fc447f614255fae8ac (diff) | |
download | hashie-54b03e8aca856a924b718e826d6bffec4c54148e.tar.gz |
Add Trash (translated hash)
-rw-r--r-- | lib/hashie.rb | 6 | ||||
-rw-r--r-- | lib/hashie/trash.rb | 55 | ||||
-rw-r--r-- | spec/hashie/trash_spec.rb | 71 |
3 files changed, 131 insertions, 1 deletions
diff --git a/lib/hashie.rb b/lib/hashie.rb index 06c238a..0a1e9ba 100644 --- a/lib/hashie.rb +++ b/lib/hashie.rb @@ -2,4 +2,8 @@ require 'hashie/hash_extensions' require 'hashie/hash' require 'hashie/mash' require 'hashie/dash' -require 'hashie/clash'
\ No newline at end of file +require 'hashie/clash' + +module Hashie + autoload :Trash, 'hashie/trash' +end diff --git a/lib/hashie/trash.rb b/lib/hashie/trash.rb new file mode 100644 index 0000000..7babcca --- /dev/null +++ b/lib/hashie/trash.rb @@ -0,0 +1,55 @@ +require 'hashie/dash' + +module Hashie + # A Trash is a 'translated' Dash where the keys can be remapped from a source + # hash. + # + # Trashes are useful when you need to read data from another application, + # such as a Java api, where the keys are named differently from how we would + # in Ruby. + class Trash < Hashie::Dash + + # Defines a property on the Trash. Options are as follows: + # + # * <tt>:default</tt> - Specify a default value for this property, to be + # returned before a value is set on the property in a new Dash. + # * <tt>:from</tt> - Specify the original key name that will be write only. + def self.property(property_name, options = {}) + super + + if options[:from] + translations << options[:from].to_sym + class_eval <<-RUBY + def #{options[:from]}=(val) + self[:#{property_name}] = val + end + RUBY + end + end + + # Set a value on the Dash in a Hash-like way. Only works + # on pre-existing properties. + def []=(property, value) + if self.class.translations.include? property.to_sym + send("#{property}=", value) + elsif property_exists? property + super + end + end + + private + + def self.translations + @translations ||= [] + end + + # Raises an NoMethodError if the property doesn't exist + # + def property_exists?(property) + unless self.class.property?(property.to_sym) + raise NoMethodError, "The property '#{property}' is not defined for this Trash." + end + true + end + end +end diff --git a/spec/hashie/trash_spec.rb b/spec/hashie/trash_spec.rb new file mode 100644 index 0000000..38fae0d --- /dev/null +++ b/spec/hashie/trash_spec.rb @@ -0,0 +1,71 @@ +require 'spec_helper' + +describe Hashie::Trash do + class TrashTest < Hashie::Trash + property :first_name, :from => :firstName + end + + let(:trash) { TrashTest.new } + + describe 'translating properties' do + it 'adds the property to the list' do + TrashTest.property :not_an_att, :from => :notAnAtt + TrashTest.properties.should include('not_an_att') + end + + it 'creates a method for reading the property' do + trash.should respond_to(:first_name) + end + + it 'creates a method for writing the property' do + trash.should respond_to(:first_name=) + end + + it 'creates a method for writing the translated property' do + trash.should respond_to(:firstName=) + end + + it 'does not create a method for reading the translated property' do + trash.should_not respond_to(:firstName) + end + end + + describe 'writing to properties' do + + it 'does not write to a non-existent property using []=' do + lambda{trash['abc'] = 123}.should raise_error(NoMethodError) + end + + it 'writes to an existing property using []=' do + lambda{trash['first_name'] = 'Bob'}.should_not raise_error + end + + it 'writes to a translated property using []=' do + lambda{trash['firstName'] = 'Bob'}.should_not raise_error + end + + it 'reads/writes to an existing property using a method call' do + trash.first_name = 'Franklin' + trash.first_name.should == 'Franklin' + end + + it 'writes to an translated property using a method call' do + trash.firstName = 'Franklin' + trash.first_name.should == 'Franklin' + end + end + + describe ' initializing with a Hash' do + it 'does not initialize non-existent properties' do + lambda{TrashTest.new(:bork => 'abc')}.should raise_error(NoMethodError) + end + + it 'sets the desired properties' do + TrashTest.new(:first_name => 'Michael').first_name.should == 'Michael' + end + + it 'sets the translated properties' do + TrashTest.new(:firstName => 'Michael').first_name.should == 'Michael' + end + end +end |