hash_dealer 1.2.6 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/Guardfile CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  guard 'rspec', :version => 2, :cli => "--color --format nested" do
5
5
  watch(%r{^spec/.+_spec\.rb$})
6
- watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec" }
7
7
  watch('spec/spec_helper.rb') { "spec" }
8
8
 
9
9
  # Rails example
data/README.rdoc CHANGED
@@ -1,8 +1,90 @@
1
- = hash_factory
1
+ = hash_dealer
2
2
 
3
- Description goes here.
3
+ == A library for creating reusable, extendable Hash-like objects for testing
4
4
 
5
- == Contributing to hash_factory
5
+ == Defining HashDealers
6
+
7
+ Everyone has a favorite Hash Dealer - here is how you create your template. Note that any method can be used in your definition
8
+
9
+ HashDealer.define(:variable) do
10
+ a("test_a")
11
+ b("test_b")
12
+ end
13
+
14
+ Once you have your HashDealer - ask him to roll one up for you
15
+
16
+ HashDealer.roll(:variable) => {:a => "test_a", :b => "test_b"}
17
+
18
+ If you'd like to customize your Hash - just pass in some options
19
+
20
+ HashDealer.roll(:variable, :a => "My own Kief") => {:a => "My own Kief", :b => "test_b"}
21
+
22
+ === Dynamic Hashes
23
+
24
+ Sometimes you'd like dynamic values for your Hash - or to use another HashDealer that you want to be dynamic - to do so, use a block inside your HashDealer definition
25
+
26
+ HashDealer.define(:dynamic) do
27
+ abc {Kernel.rand(100)}
28
+ end
29
+
30
+ HashDealer.roll(:dynamic) => {:abc => 12}
31
+ HashDealer.roll(:dynamic) => {:abc => 32}
32
+
33
+ === Nested Hashes
34
+ HashDealer does not evaluate your defined Hashes until they are called - so you can use other HashDealers that are not yet loaded in your HashDealer definitions
35
+
36
+ HashDealer.define(:b) do
37
+ hash_a(HashDealer.roll(:a))
38
+ end
39
+
40
+ HashDealer.define(:a) do
41
+ a("123")
42
+ end
43
+
44
+ HashDealer.roll(:b) => {:hash_a => {:a => "123"}}
45
+
46
+ === Inheritance
47
+
48
+ HashDealers can inherit from one another using the :parent option in their definitions
49
+
50
+ HashDealer.define(:variable_2, :parent => :variable) do
51
+ a("variable_2")
52
+ my_var("abc")
53
+ end
54
+
55
+ HashDealer.roll(:variable_2) => {:a => "variable_2", :b => "test_b", :my_var => "abc"}
56
+
57
+ === Elements other than Hashes
58
+ Sometimes you need to ask your dealer for something other than Hash - just define a root element
59
+
60
+ HashDealer.define(:crack) do
61
+ root([1,2,3])
62
+ end
63
+
64
+ HashDealer.roll(:crack) => [1,2,3]
65
+
66
+ == Rspec Matchers
67
+
68
+ One goal of HashDealer is to allow you to define dynamic matchers to ensure that JSON responses from interfacing APIs follow a consistent format
69
+
70
+ E.g.
71
+
72
+ response = {:id => 1, :name => "My Name", :email => "dan.langevin@lifebooker.com"}
73
+ {:id => 1, :name => ":name", :email => ":email"}.matcher.should match_response(response)
74
+
75
+ We don't care about the actual content of the fields, just that they are of the same type (generally) and that the hashes have the same fields
76
+
77
+ Similarly
78
+
79
+ response = [{:id => 1, :name => "My Name", :email => "dan.langevin@lifebooker.com"}, {:id => 2, :name => "Another Developer", :email => "wbartosch@lifebooker.com"}]
80
+ [{:id => 1, :name => ":name", :email => ":email"}].matcher.should match_response(response)
81
+
82
+ We don't care how many elements there are in the array (we might get back 100 records from our test), just that they have the correct format
83
+
84
+ === The matcher method
85
+ To achieve this, we use the .matcher method, which is defined on a Hash, String, Numeric and Array and should match_response(x) as an Rspec Matcher
86
+
87
+ == Contributing to hash_dealer
6
88
 
7
89
  * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
8
90
  * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
@@ -14,6 +96,6 @@ Description goes here.
14
96
 
15
97
  == Copyright
16
98
 
17
- Copyright (c) 2011 Dan Langevin. See LICENSE.txt for
99
+ Copyright (c) 2011 Lifebooker, Inc. See LICENSE.txt for
18
100
  further details.
19
101
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.6
1
+ 1.3.0
data/hash_dealer.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{hash_dealer}
8
- s.version = "1.2.6"
8
+ s.version = "1.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Dan Langevin"]
12
- s.date = %q{2011-08-25}
12
+ s.date = %q{2011-08-26}
13
13
  s.description = %q{Like Factory Girl but for Hashes only}
14
14
  s.email = %q{dan.langevin@lifebooker.com}
15
15
  s.extra_rdoc_files = [
@@ -30,6 +30,7 @@ Gem::Specification.new do |s|
30
30
  "lib/hash_dealer.rb",
31
31
  "lib/matcher.rb",
32
32
  "lib/path_string.rb",
33
+ "lib/variable_array.rb",
33
34
  "spec/lib/hash_dealer_spec.rb",
34
35
  "spec/lib/matcher_spec.rb",
35
36
  "spec/lib/path_string_spec.rb",
@@ -25,14 +25,15 @@ class String
25
25
  end
26
26
 
27
27
  class Hash
28
- def pathify_strings!
28
+ def pathify_strings
29
29
  self.each_pair do |k,v|
30
30
  if v.is_a?(Array) || v.is_a?(Hash)
31
- v.pathify_strings!
31
+ self[k] = v.pathify_strings
32
32
  elsif v.instance_of?(String) || v.is_a?(Numeric)
33
33
  self[k] = PathString.new(URI.decode(v.to_s))
34
34
  end
35
35
  end
36
+ self
36
37
  end
37
38
  # recursively get a matcher for each value
38
39
  def matcher(opts = {})
@@ -52,17 +53,35 @@ class Hash
52
53
  end
53
54
  end
54
55
  class Array
55
- def pathify_strings!
56
- self.each_with_index do |v,k|
57
- if v.is_a?(Array) || v.is_a?(Hash)
58
- v.pathify_strings!
56
+ def pathify_strings
57
+ if self.first == ":matcher"
58
+ val = VariableArray.new(self)
59
+ else
60
+ val = self
61
+ end
62
+ val.each_with_index do |v,k|
63
+ if v.is_a?(Array) || v.is_a?(Hash)
64
+ val[k] = v.pathify_strings
59
65
  elsif v.instance_of?(String) || v.is_a?(Numeric)
60
- self[k] = PathString.new(URI.decode(v.to_s))
66
+ val[k] = PathString.new(URI.decode(v.to_s))
61
67
  end
62
68
  end
69
+ val
63
70
  end
64
71
  # call matcher on all of the elements
65
72
  def matcher(opts = {})
66
- self.collect(&:matcher)
73
+ self.unshift(":matcher")
74
+ VariableArray.new(self.collect(&:matcher))
67
75
  end
68
- end
76
+ # we want this to apply to both :eql? and ==
77
+ alias_method :eql?, :==
78
+ # we want this to add decorator behavior to ==, proxying to VariableArray if possible
79
+ define_method "==_with_variable_array" do |other|
80
+ return other == self if other.is_a?(VariableArray)
81
+ self.send("==_without_variable_array",other)
82
+ end
83
+ # Equivalent to:
84
+ # alias_method_chain "==", "variable_array"
85
+ alias_method "==_without_variable_array", :==
86
+ alias_method :==, "==_with_variable_array"
87
+ end
data/lib/hash_dealer.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require File.expand_path('../path_string', __FILE__)
2
+ require File.expand_path('../variable_array', __FILE__)
2
3
  require File.expand_path('../core_extensions', __FILE__)
3
4
  require File.expand_path('../matcher', __FILE__)
4
5
 
@@ -13,11 +14,12 @@ class HashDealer
13
14
 
14
15
  # define a method of the request factory
15
16
  def self.define(name, opts = {}, &block)
16
- self.hashes[name] = self.new(opts, &block)
17
+ self.hashes[name] = [opts, block]
17
18
  end
18
19
 
19
20
  def self.roll(name, *args)
20
21
  raise Exception.new("No HashDealer called #{name}") unless self.hashes[name]
22
+ self.hashes[name] = self.new(self.hashes[name][0], &self.hashes[name][1]) unless self.hashes[name].is_a?(HashDealer)
21
23
  self.hashes[name]._attributes(*args)
22
24
  end
23
25
 
data/lib/path_string.rb CHANGED
@@ -28,7 +28,7 @@ class PathString < String
28
28
 
29
29
  def self.as_sorted_json(val)
30
30
  val = self.sort_json(val)
31
- val.pathify_strings!
31
+ val = val.pathify_strings
32
32
  val
33
33
  end
34
34
 
@@ -0,0 +1,11 @@
1
+ class VariableArray < Array
2
+ def ==(other)
3
+ if other.is_a?(Array)
4
+ comp = self[1..(self.length - 1)]
5
+ return true if comp.first == other.first
6
+ else
7
+ super
8
+ end
9
+ end
10
+ alias_method :eql?, :==
11
+ end
@@ -130,4 +130,15 @@ describe HashDealer do
130
130
  HashDealer.roll(:test)[:attributes].should eql("test")
131
131
  HashDealer.roll(:test).matcher[:attributes].should eql(":test")
132
132
  end
133
+
134
+ it "should allow the use of a HashDealer in the definition of another before the first is defined" do
135
+ HashDealer.define(:b) do
136
+ hash_a(HashDealer.roll(:a))
137
+ end
138
+ HashDealer.define(:a) do
139
+ a("123")
140
+ end
141
+ HashDealer.roll(:b).should eql({:hash_a => {:a => "123"}})
142
+ end
143
+
133
144
  end
@@ -14,4 +14,9 @@ describe "match_resonse Matcher" do
14
14
  {"a" => ":b"}.should match_list([{"a" => "test"}, {"a" => "test2"}])
15
15
  end
16
16
 
17
+ it "should match using wildcards for variable length arrays" do
18
+ {"a" => ["a"]}.matcher.should match_response({"a" => ["a", "b", "c", "d"]})
19
+ {"a" => [{"a" => "b"}]}.matcher.should match_response({"a" => [{"a" => "c"},{"a" => "x"},{"a" => "y"}]})
20
+ end
21
+
17
22
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: hash_dealer
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 1.2.6
5
+ version: 1.3.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Dan Langevin
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-08-25 00:00:00 Z
13
+ date: 2011-08-26 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
@@ -112,6 +112,7 @@ files:
112
112
  - lib/hash_dealer.rb
113
113
  - lib/matcher.rb
114
114
  - lib/path_string.rb
115
+ - lib/variable_array.rb
115
116
  - spec/lib/hash_dealer_spec.rb
116
117
  - spec/lib/matcher_spec.rb
117
118
  - spec/lib/path_string_spec.rb
@@ -129,7 +130,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
129
130
  requirements:
130
131
  - - ">="
131
132
  - !ruby/object:Gem::Version
132
- hash: -3331694246731303035
133
+ hash: -979585820027461548
133
134
  segments:
134
135
  - 0
135
136
  version: "0"