summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLes Hill and Paul Elliott <dev+leshill+paulelliott@hashrocket.com>2010-07-30 05:30:47 +0800
committerMichael Bleigh <michael@intridea.com>2010-08-10 22:57:12 +0800
commit54b03e8aca856a924b718e826d6bffec4c54148e (patch)
treeb5b118324bf8e6cd1ebc79b88be703b3efdea96a
parent4beb2bd9c4fd552423b205fc447f614255fae8ac (diff)
downloadhashie-54b03e8aca856a924b718e826d6bffec4c54148e.tar.gz
Add Trash (translated hash)
-rw-r--r--lib/hashie.rb6
-rw-r--r--lib/hashie/trash.rb55
-rw-r--r--spec/hashie/trash_spec.rb71
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