htransform 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in htransform.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,149 @@
1
+ HTransform
2
+ ======
3
+
4
+ HTransform provides a simple DSL to transform a supplied hash with an arbitrary structure to another hash with an even more arbitrary structure.
5
+
6
+ ***Note:*** *HTransform does not simply modify the hash you have passed in. It actually creates a new hash from scratch. It only copies or does transformations on the fields you specify in the transform block.*
7
+
8
+ Support
9
+ =======
10
+
11
+ Should work for both 1.8 and 1.9 rubies.
12
+
13
+ Install
14
+ =======
15
+
16
+ Standard gem install.
17
+
18
+ gem install htransform
19
+
20
+
21
+ Put this in your Gemfile.
22
+
23
+ gem "htransform"
24
+
25
+ or
26
+
27
+ gem "htransform", :git =>
28
+ "git://github.com/joshkrueger/htransform.git"
29
+
30
+ Basic Usage
31
+ ===========
32
+
33
+ All you have to do is create a new class and inherit from HTransform.
34
+
35
+ class ExampleHTransform < HTransform
36
+ end
37
+
38
+ Inside your new class you just use the hopefully not-convoluted DSL.
39
+
40
+ class ExampleHTransform < HTransform
41
+ transform do
42
+ input :from => "foo", :to => :bar
43
+ end
44
+ end
45
+
46
+ Theres also shorthand for you lazy folks.
47
+
48
+ input "foo" => :bar
49
+
50
+ But how do I do more than just re-name my keys?
51
+
52
+ Let's start simple. Lets take the following hash
53
+
54
+ { "foo" => "party" }
55
+
56
+ and have HTransform change it to
57
+
58
+ { :foo => "Party" }
59
+
60
+ Its pretty easy!
61
+
62
+ input "foo" => :foo, :via => :capitalize
63
+
64
+ See! Nice and simple!
65
+
66
+ HTransform with a block!
67
+
68
+ input "foo" => :foo, :via => lambda { |x| x.capitalize }
69
+
70
+ Actually Using HTransform
71
+ ================
72
+
73
+ So we have our ExampleHTransform we created above (with our capitalize transform), saved somewhere. Lets say its in your "lib" folder. Anywhere it's loadable via require should be fine.
74
+
75
+ require 'htransform'
76
+ require 'example_htransform'
77
+
78
+ contrived_input_hash = { "foo" => "bar" }
79
+
80
+ output_hash = ExampleHTransform.convert(contrived_input_hash)
81
+
82
+ and now output_hash should look like
83
+
84
+ { :foo => "Bar" }
85
+
86
+ Slightly Less Basic Usage
87
+ =================
88
+
89
+ Want to combine multiple input keys? **HTransform CAN DO THAT**
90
+
91
+ input_multiple ["foo", "bar"] => :foo_bar
92
+
93
+ By default HTransform will just join the multiple elements with a space. i.e. "foo" and "bar" become "foo bar". Need something more complicated?
94
+
95
+ input_multiple ["foo", "bar"] => :foo_bar, :via => lambda { |x| x.map{ |v| v.capitalize }.join(" ") }
96
+
97
+ Here, "foo" and "bar" become "Foo Bar". Easy right?
98
+
99
+ Hrmm. What about nested hashes? No problem. Just define the nesting order in an array.
100
+
101
+ Lets start with nested inputs. Given the hash
102
+
103
+ { "foo" => { "bar" => "sample text" } }
104
+
105
+ and a desired hash of
106
+
107
+ { "example" => "sample text" }
108
+
109
+ we would give HTransform the following operation
110
+
111
+ input ["foo", "bar"] => "example"
112
+
113
+ If we want the opposite, all we do is reverse it.
114
+
115
+ input "example" => ["foo", "bar"]
116
+
117
+ Nested to nested?
118
+
119
+ input ["foo", "bar"] => ["baz", "qux"]
120
+
121
+ this turns
122
+
123
+ { "foo" => { "bar" => "hello world" } }
124
+
125
+ into
126
+
127
+ { "baz" => { "qux" => "hello world" } }
128
+
129
+ Want to combine multiple inputs when one or more are an array?
130
+
131
+ input [ [ "foo", "bar" ], "baz" ] => "combined nested hash"
132
+
133
+ Shorthand Limitations
134
+ ==============
135
+
136
+ Hey, the shorthand isn't perfect and theres really only a couple scenarios I can think of. If you have a key on your input hash of :via, you can't use the shorthand.
137
+
138
+ input :via => :not_via
139
+
140
+ That won't work. Why? **I'm lazy** So just use the long format.
141
+
142
+ input :from => :via, :to => :not_via, :via => :capitalize
143
+
144
+ However, :from or :to will work just fine in the shorthand. The longhand syntax only works if both the :from and :to symbols are passed in.
145
+
146
+ input :from => "from"
147
+
148
+ That will work.
149
+
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'bundler'
2
+
3
+ Bundler::GemHelper.install_tasks
4
+
5
+ require "rspec"
6
+ require "rspec/core/rake_task"
7
+
8
+ RSpec::Core::RakeTask.new do |t|
9
+ t.rspec_opts = %w(--format documentation --color)
10
+ t.pattern = 'spec/**/*_spec.rb'
11
+ end
12
+
13
+ task :default => ["spec"]
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'htransform'
4
+ require 'example_transform'
5
+
6
+ in_hash = {
7
+ "fname" => "JOHN",
8
+ "lname" => "doe",
9
+ "phonenum" => "555-123-1122",
10
+ "email" => "j.doe@example.com",
11
+ "state_id" => {
12
+ "number" => "d123456",
13
+ "state" => "il",
14
+ "type" => "drivers"
15
+ }
16
+ }
17
+
18
+ desired_hash = {
19
+ :first_name => "John",
20
+ :last_name => "Doe",
21
+ :full_name => "John Doe",
22
+ :contact_info => {
23
+ :phone_number => "5551231122",
24
+ :email_address => "j.doe@example.com"
25
+ },
26
+ :state_identification => {
27
+ :issuing_state => "IL",
28
+ :type => "drivers",
29
+ :number => "D123456"
30
+ }
31
+ }
32
+
33
+ result_hash = ExampleTransform.convert(in_hash)
34
+
35
+ puts "The Hash Transformation worked correctly!" if result_hash == desired_hash
@@ -0,0 +1,18 @@
1
+ require 'htransform'
2
+
3
+ class ExampleTransform < HTransform
4
+ transform do
5
+
6
+ input "fname" => :first_name, :via => :capitalize
7
+ input :from => "lname", :to => :last_name, :via => lambda { |x| x.capitalize }
8
+ input "phonenum" => [:contact_info, :phone_number], :via => lambda { |p| p.gsub("-", "") }
9
+ input "email" => [:contact_info, :email_address]
10
+
11
+ input_multiple :from => ["fname", "lname"], :to => :full_name, :via => lambda { |x| x.map{ |v| v.capitalize }.join(" ") }
12
+
13
+ input ["state_id", "state"] => [:state_identification, :issuing_state], :via => :upcase
14
+ input ["state_id", "number"] => [:state_identification, :number], :via => :upcase
15
+ input ["state_id", "type"] => [:state_identification, :type]
16
+
17
+ end
18
+ end
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "htransform/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "htransform"
7
+ s.version = HTransform::VERSION
8
+ s.authors = ["Josh Krueger"]
9
+ s.email = ["joshsinbox@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{HTransform transforms your hashes}
12
+ s.description = %q{HTransform provides a simple DSL to transform arbitrary hashes into another, more arbitrary hash. Yay.}
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ s.add_development_dependency("rspec", "~> 2.5.0")
20
+ s.add_development_dependency("rake")
21
+ end
@@ -0,0 +1,3 @@
1
+ class HTransform
2
+ VERSION = "0.8.0"
3
+ end
data/lib/htransform.rb ADDED
@@ -0,0 +1,198 @@
1
+ require "htransform/version"
2
+
3
+ class HTransform
4
+
5
+ ValueNotPresentError = Class.new(StandardError)
6
+
7
+ class << self
8
+ attr_reader :transform_block
9
+
10
+ attr_reader :input_nest
11
+ attr_reader :output_nest
12
+
13
+ def convert(input_hash)
14
+ new.convert(input_hash)
15
+ end
16
+
17
+ def transform(&trans_block)
18
+ @transform_block = trans_block
19
+ end
20
+
21
+ end
22
+
23
+ def initialize
24
+ @output_hash = Hash.new { |h,k| h[k] = Hash.new(&h.default_proc) }
25
+ @input_nest = []
26
+ @output_nest = []
27
+ end
28
+
29
+ def convert(input)
30
+
31
+ unless input.is_a? Hash
32
+ if input.respond_to? :to_hash
33
+ input = input.to_hash
34
+ else
35
+ raise ArgumentError "object is not a Hash or does not respond to to_hash"
36
+ end
37
+ end
38
+
39
+ @input_hash = input
40
+ instance_exec(&self.class.transform_block)
41
+ Hash[@output_hash]
42
+ end
43
+
44
+ private
45
+
46
+ def set_val(dst, val)
47
+
48
+ dst = (@output_nest + [dst]).flatten unless @output_nest.empty?
49
+
50
+ if dst.is_a? Array
51
+ last_key = dst.pop
52
+ dst.reduce(@output_hash) { |h,k| h[k] }[last_key] = val
53
+ else
54
+ @output_hash[dst] = val
55
+ end
56
+ end
57
+
58
+ def get_val(src)
59
+ return get_val!(src)
60
+ rescue ValueNotPresentError
61
+ return nil
62
+ end
63
+
64
+ def get_val!(src)
65
+
66
+ src = (@input_nest + [src]).flatten unless @input_nest.empty?
67
+
68
+ if src.is_a? Array
69
+ src.reduce(@input_hash) { |h,k| h[k] }
70
+ else
71
+ if @input_hash.key?(src)
72
+ @input_hash[src]
73
+ else
74
+ raise ValueNotPresentError
75
+ end
76
+ end
77
+ end
78
+
79
+ def key_present?(src)
80
+ src = (@input_nest + [src]).flatten unless @input_nest.empty?
81
+ if src.is_a? Array
82
+ src.reduce(@input_hash) do |h, k|
83
+ h[k].is_a?(Hash) ? h[k] : h.has_key?(k)
84
+ end
85
+ else
86
+ @input_hash.key?(src)
87
+ end
88
+ end
89
+
90
+ def parse_options(options)
91
+ from, to, via, default = nil
92
+
93
+ via = options.delete :via
94
+ default = options.delete :default
95
+
96
+ from, to = if options.key? :from and options.key? :to
97
+ [options[:from], options[:to]]
98
+ else
99
+ options.delete :from
100
+ options.delete :to
101
+
102
+ lazy_args = options.shift
103
+ if lazy_args.is_a? Array and lazy_args.length == 2
104
+ lazy_args
105
+ end
106
+ end
107
+
108
+ [from, to, via, default]
109
+ end
110
+
111
+ def passthrough(*options)
112
+ options.each do |k|
113
+ begin
114
+ input_value = get_val!(k)
115
+ set_val(k, input_value)
116
+ rescue ValueNotPresentError
117
+ end
118
+ end
119
+ end
120
+
121
+ def input_multiple(options)
122
+ from, to, via, default = parse_options(options)
123
+ via = lambda { |x| x.join(" ") } if via.nil?
124
+
125
+
126
+ old_values = from.map{ |k| get_val(k) }
127
+ new_value = if via.is_a? Proc
128
+ via.call old_values
129
+ elsif via.is_a? Symbol
130
+ if methods.include? via.to_s or methods.include? via
131
+ via_method = method(via)
132
+ if via_method.arity != 1
133
+ via_method.call(*old_values)
134
+ else
135
+ via_method.call(old_values)
136
+ end
137
+ else
138
+ old_values.send(via)
139
+ end
140
+ end
141
+
142
+
143
+ set_val(to, new_value)
144
+ end
145
+
146
+ def input(options)
147
+ from, to, via, default = parse_options(options)
148
+ return if !key_present?(from) && default.nil?
149
+
150
+ new_value = if get_val(from).nil? && !default.nil?
151
+ default.respond_to?(:call) ? default.call : default
152
+ elsif via.is_a? Proc
153
+ via.call get_val(from)
154
+ elsif via.is_a? Symbol
155
+ if methods.include? via.to_s or methods.include? via
156
+ via_method = method(via)
157
+ if via_method.arity != 1
158
+ method(via).call(*get_val(from))
159
+ else
160
+ method(via).call(get_val(from))
161
+ end
162
+ else
163
+ get_val(from).send(via)
164
+ end
165
+ else
166
+ get_val(from)
167
+ end
168
+
169
+ set_val(to, new_value)
170
+ end
171
+
172
+ def insert(options)
173
+ options.each { |key, value| set_val(key, value) }
174
+ end
175
+
176
+ def nested(options, &trans_block)
177
+
178
+ if options.is_a? Symbol
179
+ options = {:key => options, :type => "output"}
180
+ else
181
+ options[:type] = "output" unless options.key? :type
182
+ end
183
+
184
+ if options[:type] == "output" or options[:type] == "input"
185
+ type = options[:type]
186
+ if options[:key]
187
+ key = options[:key]
188
+ nest_var = "@#{type}_nest"
189
+ self.instance_variable_set(:"#{nest_var}", self.instance_variable_get(:"#{nest_var}") + [key].flatten)
190
+
191
+ instance_exec(&trans_block)
192
+
193
+ self.instance_variable_set(:"#{nest_var}", self.instance_variable_get(:"#{nest_var}") - [key].flatten)
194
+ end
195
+ end
196
+ end
197
+
198
+ end
@@ -0,0 +1,108 @@
1
+ require 'spec_helper'
2
+ require 'date'
3
+
4
+ describe HTransform do
5
+ describe "convert" do
6
+ context "using the nested block" do
7
+
8
+ it "defaults to output nesting" do
9
+ class TestHTransform < HTransform
10
+ transform do
11
+ nested :key => :foo_nest do
12
+ input "foo" => :foo
13
+ end
14
+ end
15
+ end
16
+
17
+ input_hash = { "foo" => "bar" }
18
+ desired_hash = { :foo_nest => { :foo => "bar" } }
19
+
20
+ result = TestHTransform.convert(input_hash)
21
+
22
+ result.should == desired_hash
23
+ end
24
+
25
+ it "uses output nested when specified" do
26
+ class TestHTransform < HTransform
27
+ transform do
28
+ nested :type => "output", :key => :foo_nest do
29
+ input "foo" => :foo
30
+ end
31
+ end
32
+ end
33
+
34
+ input_hash = { "foo" => "bar" }
35
+ desired_hash = { :foo_nest => { :foo => "bar" } }
36
+
37
+ result = TestHTransform.convert(input_hash)
38
+
39
+ result.should == desired_hash
40
+ end
41
+
42
+ it "uses input nesting when specified" do
43
+ class TestHTransform < HTransform
44
+ transform do
45
+ nested :type => "input", :key => :nested_data do
46
+ input "foo" => :foo
47
+ end
48
+ end
49
+ end
50
+
51
+ input_hash = { :nested_data => { "foo" => "bar" } }
52
+ desired_hash = { :foo => "bar" }
53
+
54
+ result = TestHTransform.convert(input_hash)
55
+
56
+ result.should == desired_hash
57
+ end
58
+
59
+ it "can nest multiple nested blocks of different types" do
60
+ class TestHTransform < HTransform
61
+ transform do
62
+ nested :type => "input", :key => :nested_input do
63
+ input :foo_nest => :foo
64
+ input :bar_nest => :bar
65
+
66
+ nested :type => "input", :key => :more_nesting do
67
+ nested :type => "output", :key => :nested do
68
+ input :foobar => :foo_bar
69
+ end
70
+ end
71
+ end
72
+
73
+ nested :key => :animal_sounds do
74
+ passthrough :cat, :dog
75
+ end
76
+ end
77
+ end
78
+
79
+ input_hash = { :nested_input => { :foo_nest => "foo!", :bar_nest => "bar!", :more_nesting => { :foobar => "meh"} },
80
+ :cat => "meow!", :dog => "woof!" }
81
+
82
+ desired_hash = { :foo => "foo!", :bar => "bar!", :nested => { :foo_bar => "meh"} , :animal_sounds => { :cat => "meow!", :dog => "woof!" } }
83
+
84
+ result = TestHTransform.convert(input_hash)
85
+
86
+ result.should == desired_hash
87
+ end
88
+
89
+ it "can use the shorthand method and default to output nesting" do
90
+ class TestHTransform < HTransform
91
+ transform do
92
+ nested :out_nest do
93
+ input "foo" => :foo
94
+ end
95
+ end
96
+ end
97
+
98
+ input_hash = { "foo" => "bar" }
99
+ desired_hash = { :out_nest => { :foo => "bar" } }
100
+
101
+ result = TestHTransform.convert(input_hash)
102
+
103
+ result.should == desired_hash
104
+ end
105
+
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,392 @@
1
+ require 'spec_helper'
2
+ require 'date'
3
+
4
+ describe HTransform do
5
+ describe "convert" do
6
+ it "returns real hashes" do
7
+ class TestHTransform < HTransform
8
+ transform do
9
+ input "foo" => :baz
10
+ end
11
+ end
12
+
13
+ input_hash = { "foo" => "bar" }
14
+ result = TestHTransform.convert(input_hash)
15
+ result[:missing].should be_nil
16
+ end
17
+
18
+ it "can call instance methods from :via" do
19
+ class TestHTransform < HTransform
20
+ transform do
21
+ input "foo" => :foo, :via => lambda { |value| my_method(value) }
22
+ end
23
+ def my_method(value); value.reverse; end
24
+ end
25
+
26
+ input_hash = { "foo" => "bar" }
27
+ TestHTransform.convert(input_hash).should == { :foo => "rab" }
28
+ end
29
+
30
+ context "via is a symbol" do
31
+ it "can call instance methods via a symbol" do
32
+ class TestHTransform < HTransform
33
+ transform do
34
+ input "foo" => :foo, :via => :single_arg_method
35
+ input_multiple ["num1", "num2"] => :diff, :via => :multi_arg_method
36
+ input :nums => :diff2, :via => :multi_arg_method
37
+ input :nums => :splat_1, :via => :splat_method
38
+ input "foo" => :foo_splat, :via => :splat_method
39
+ end
40
+
41
+ def single_arg_method(value); value.reverse; end
42
+ def multi_arg_method(value1, value2); value1 - value2; end
43
+ def splat_method(*arg); arg.join(", "); end
44
+ end
45
+
46
+ input_hash = { "foo" => "bar", "num1" => 100, "num2" => 50, :nums => [100, 50] }
47
+
48
+ desired_hash = {:foo => "rab", :diff => 50, :diff2 => 50, :splat_1 => "100, 50", :foo_splat => "bar" }
49
+ TestHTransform.convert(input_hash).should == desired_hash
50
+ end
51
+ end
52
+
53
+ context "the input key is missing" do
54
+ it "does not set it in the output" do
55
+ class TestHTransform < HTransform
56
+ transform do
57
+ input "birth_date" => :birthday, :via => lambda { |d| d.strftime('%F') }
58
+ end
59
+ end
60
+
61
+ input_hash = { "foo" => "bar" }
62
+ TestHTransform.convert(input_hash).should == {}
63
+ end
64
+
65
+ context "the input key is present but the value is nil" do
66
+ it "does set it in the input" do
67
+ class TestHTransform < HTransform
68
+ transform do
69
+ input "foo" => :bar
70
+ end
71
+ end
72
+
73
+ input_hash = { "foo" => nil }
74
+ desired_hash = { :bar => nil }
75
+
76
+ TestHTransform.convert(input_hash).should == desired_hash
77
+ end
78
+ end
79
+
80
+ it "can set a default value" do
81
+ class TestHTransform < HTransform
82
+ transform do
83
+ input "birth_date" => :birthday, :default => Date.today
84
+ input "death_date" => :deathday, :default => lambda { Date.today + 5 }
85
+ end
86
+ end
87
+
88
+ input_hash = { "foo" => "bar" }
89
+ desired_hash = { :birthday => Date.today, :deathday => Date.today + 5 }
90
+
91
+ TestHTransform.convert(input_hash).should == desired_hash
92
+ end
93
+ end
94
+
95
+ context "inserting keys" do
96
+ it "should insert the key regardless of the input hash" do
97
+ class TestHTransform < HTransform
98
+ transform do
99
+ insert :bar => 'bar', :quux => 'quux'
100
+ end
101
+ end
102
+
103
+ input_hash = { "foo" => "foo" }
104
+ desired_hash = { :bar => 'bar', :quux => 'quux' }
105
+ TestHTransform.convert(input_hash).should == desired_hash
106
+ end
107
+ end
108
+
109
+ context "the value has no transform" do
110
+ it "should produce the same key (string)" do
111
+ class TestHTransform < HTransform
112
+ transform do
113
+ input :from => "foo", :to => "foo"
114
+ end
115
+ end
116
+
117
+ input_hash = { "foo" => "bar" }
118
+
119
+ TestHTransform.convert(input_hash).should == input_hash
120
+ end
121
+
122
+ it "should produce the same key via shorthand (symbol)" do
123
+ class TestHTransform < HTransform
124
+ transform do
125
+ input :foo => :foo
126
+ end
127
+ end
128
+
129
+ input_hash = { :foo => :bar }
130
+
131
+ TestHTransform.convert(input_hash).should == input_hash
132
+ end
133
+
134
+ it "should change the key (string to symbol)" do
135
+ class TestHTransform < HTransform
136
+ transform do
137
+ input "foo" => :foo
138
+ end
139
+ end
140
+
141
+ input_hash = { "foo" => "bar" }
142
+ desired_hash = { :foo => "bar" }
143
+
144
+ TestHTransform.convert(input_hash).should == desired_hash
145
+ end
146
+
147
+ it "should change the key (symbox to key)" do
148
+ class TestHTransform < HTransform
149
+ transform do
150
+ input :foo => "foo"
151
+ end
152
+ end
153
+
154
+ desired_hash = { "foo" => "bar" }
155
+ input_hash = { :foo => "bar" }
156
+
157
+ TestHTransform.convert(input_hash).should == desired_hash
158
+ end
159
+
160
+ end
161
+
162
+ context "the value should be capitalized" do
163
+ it "should produce the same key" do
164
+ class TestHTransform < HTransform
165
+ transform do
166
+ input "foo" => "foo", :via => :capitalize
167
+ end
168
+ end
169
+
170
+ input_hash = { "foo" => "bar" }
171
+ desired_hash = { "foo" => "Bar" }
172
+
173
+ TestHTransform.convert(input_hash).should == desired_hash
174
+ end
175
+
176
+ it "should produce a different key" do
177
+ class TestHTransform < HTransform
178
+ transform do
179
+ input "foo" => :foo, :via => lambda { |x| x.capitalize }
180
+ end
181
+ end
182
+
183
+ input_hash = { "foo" => "bar" }
184
+ desired_hash = { :foo => "Bar" }
185
+
186
+ TestHTransform.convert(input_hash).should == desired_hash
187
+ end
188
+
189
+ end
190
+
191
+ context "use nested input" do
192
+ it "should produce the same key without nesting" do
193
+ class TestHTransform < HTransform
194
+ transform do
195
+ input ["foo", "bar"] => "bar"
196
+ end
197
+ end
198
+
199
+ input_hash = { "foo" => { "bar" => "FOOBAR!" } }
200
+ desired_hash = { "bar" => "FOOBAR!" }
201
+
202
+ TestHTransform.convert(input_hash).should == desired_hash
203
+ end
204
+
205
+ it "should produce a different key without nesting" do
206
+ class TestHTransform < HTransform
207
+ transform do
208
+ input ["foo", "bar"] => :foo_bar
209
+ end
210
+ end
211
+
212
+ input_hash = { "foo" => { "bar" => "FOOBAR!" } }
213
+ desired_hash = { :foo_bar => "FOOBAR!" }
214
+
215
+ TestHTransform.convert(input_hash).should == desired_hash
216
+ end
217
+ end
218
+
219
+ context "use nested output" do
220
+ it "should produce the same key, but nested" do
221
+ class TestHTransform < HTransform
222
+ transform do
223
+ input :foo => [:bar, :foo]
224
+ end
225
+ end
226
+
227
+ input_hash = { :foo => "FOO!" }
228
+ desired_hash = { :bar => { :foo => "FOO!" } }
229
+
230
+ TestHTransform.convert(input_hash).should == desired_hash
231
+ end
232
+
233
+ it "should produce a different key, but nested" do
234
+ class TestHTransform < HTransform
235
+ transform do
236
+ input "foo" => [:bar, :foo]
237
+ end
238
+ end
239
+
240
+ input_hash = { "foo" => "FOO!" }
241
+ desired_hash = { :bar => { :foo => "FOO!" } }
242
+
243
+ TestHTransform.convert(input_hash).should == desired_hash
244
+ end
245
+
246
+ it "should produce a different key, but nested (with string keys)" do
247
+ class TestHTransform < HTransform
248
+ transform do
249
+ input "foo" => ["bar", "foo"]
250
+ end
251
+ end
252
+
253
+ input_hash = { "foo" => "FOO!" }
254
+ desired_hash = { "bar" => { "foo" => "FOO!" } }
255
+
256
+ TestHTransform.convert(input_hash).should == desired_hash
257
+ end
258
+
259
+ it "should use nested input and produce the same key, but nested differently" do
260
+ class TestHTransform < HTransform
261
+ transform do
262
+ input ["foo", "bar"] => ["baz", "bar"]
263
+ end
264
+ end
265
+
266
+ input_hash = { "foo" => { "bar" => "BAR!" } }
267
+ desired_hash = { "baz" => { "bar" => "BAR!" } }
268
+
269
+ TestHTransform.convert(input_hash).should == desired_hash
270
+ end
271
+
272
+ it "should use nested input and produce a different key, but nested differently" do
273
+ class TestHTransform < HTransform
274
+ transform do
275
+ input ["foo", "bar"] => [:baz, :bar]
276
+ end
277
+ end
278
+
279
+ input_hash = { "foo" => { "bar" => "BAR!" } }
280
+ desired_hash = { :baz => { :bar => "BAR!" } }
281
+
282
+ TestHTransform.convert(input_hash).should == desired_hash
283
+ end
284
+ end
285
+
286
+ context "use multiple inputs" do
287
+ it "should join two elements with a space and produce a single key" do
288
+ class TestHTransform < HTransform
289
+ transform do
290
+ input_multiple [:foo, :bar] => :foo_bar
291
+ end
292
+ end
293
+
294
+ input_hash = { :foo => "Foo", :bar => "Bar" }
295
+ desired_hash = { :foo_bar => "Foo Bar" }
296
+
297
+ TestHTransform.convert(input_hash).should == desired_hash
298
+ end
299
+
300
+ it "should join two nested elements with a dash, via a lambda and produce a single key" do
301
+ class TestHTransform < HTransform
302
+ transform do
303
+ input_multiple [[:foo, :bar], [:baz, :qux]] => :bar_qux, :via => lambda { |x| x.join("-") }
304
+ end
305
+ end
306
+
307
+ input_hash = { :foo => { :bar => "fbar" }, :baz => { :qux => "bqux" } }
308
+ desired_hash = { :bar_qux => "fbar-bqux" }
309
+
310
+ TestHTransform.convert(input_hash).should == desired_hash
311
+ end
312
+ end
313
+
314
+ end
315
+
316
+ context "multiple htransforms" do
317
+ it "does not share transformations between unrelated subclasses" do
318
+ class HTransformA < HTransform
319
+ transform do
320
+ input "foo" => :foo
321
+ end
322
+ end
323
+
324
+ class HTransformB < HTransform
325
+ transform do
326
+ input "bar" => :bar
327
+ end
328
+ end
329
+
330
+ input_hash = { "foo" => "fooval", "bar" => "barval" }
331
+ HTransformA.convert(input_hash).should == { :foo => "fooval" }
332
+ HTransformB.convert(input_hash).should == { :bar => "barval" }
333
+ end
334
+ end
335
+
336
+ context "passthrough" do
337
+
338
+ it "ignores a passthrough'd key if it is absent" do
339
+ class TestHTransform < HTransform
340
+ transform do
341
+ passthrough :foo
342
+ input :bar => :bar_key
343
+ end
344
+ end
345
+
346
+ input_hash = { :bar => 'one' }
347
+ desired_hash = { :bar_key => 'one' }
348
+
349
+ result = TestHTransform.convert(input_hash)
350
+ result.should == desired_hash
351
+ end
352
+
353
+ it "does not ignore the passthrough key if it is present but nil" do
354
+ class TestHTransform < HTransform
355
+ transform do
356
+ passthrough :foo
357
+ input :bar => :bar_key
358
+ end
359
+ end
360
+
361
+ input_hash = { :bar => 'one', :foo => nil }
362
+ desired_hash = { :bar_key => 'one', :foo => nil }
363
+
364
+ result = TestHTransform.convert(input_hash)
365
+ result.should == desired_hash
366
+ end
367
+
368
+ end
369
+
370
+ context "non-hashes" do
371
+ it "works with objects that respond to to_hash" do
372
+ class TestHTransform < HTransform
373
+ transform do
374
+ passthrough :foo
375
+ input :bar => :bar_key
376
+ end
377
+ end
378
+
379
+ class NonHash
380
+ def to_hash
381
+ { :foo => "FOO", :bar => 'BAR' }
382
+ end
383
+ end
384
+
385
+ input_object = NonHash.new
386
+ desired_hash = { :bar_key => 'BAR', :foo => "FOO" }
387
+
388
+ result = TestHTransform.convert(input_object)
389
+ result.should == desired_hash
390
+ end
391
+ end
392
+ end
@@ -0,0 +1 @@
1
+ require 'htransform'
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: htransform
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.8.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Josh Krueger
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-08-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 2.5.0
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 2.5.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: HTransform provides a simple DSL to transform arbitrary hashes into another,
47
+ more arbitrary hash. Yay.
48
+ email:
49
+ - joshsinbox@gmail.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - .gitignore
55
+ - Gemfile
56
+ - README.md
57
+ - Rakefile
58
+ - examples/example.rb
59
+ - examples/example_htransform.rb
60
+ - htransform.gemspec
61
+ - lib/htransform.rb
62
+ - lib/htransform/version.rb
63
+ - spec/htransform_nested_spec.rb
64
+ - spec/htransform_spec.rb
65
+ - spec/spec_helper.rb
66
+ homepage: ''
67
+ licenses: []
68
+ post_install_message:
69
+ rdoc_options: []
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ! '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubyforge_project:
86
+ rubygems_version: 1.8.23
87
+ signing_key:
88
+ specification_version: 3
89
+ summary: HTransform transforms your hashes
90
+ test_files:
91
+ - spec/htransform_nested_spec.rb
92
+ - spec/htransform_spec.rb
93
+ - spec/spec_helper.rb
94
+ has_rdoc: