hash-proxy 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,7 @@
1
+ # == Version 0.1.0 / 2012-06-12
2
+ # * include Enumerable in Proxy
3
+ # * Add some hash-like semantics to Proxy
4
+ #
1
5
  # == Version 0.0.4 / 2012-06-08
2
6
  # * Add #to_str to NullObject to avoid some rspec errors
3
7
  #
data/README.md CHANGED
@@ -25,11 +25,20 @@ Features
25
25
  Examples
26
26
  --------
27
27
 
28
- require 'hash-proxy'
28
+ require 'hash_proxy'
29
29
  hash = {foo: 'bar', baz: [{key: 'value', key2: 2, key3: [1,2,3]}, {key: 'value2', key2: 22, key3: [4,5,6]}], bip: 'bop'}
30
30
  proxy = HashProxy.create_from(hash)
31
31
  proxy.baz.last.key3.should == [4,5,6]
32
32
 
33
+ Also supports hash like semantics:
34
+
35
+ proxy[:foo] => 'bar'
36
+ proxy[:newkey] = 'new value'
37
+
38
+ proxy.each do |k, v|
39
+ puts "#{k}: #{v}"
40
+ end
41
+
33
42
  Requirements
34
43
  ------------
35
44
 
@@ -5,6 +5,7 @@ module HashProxy
5
5
  # hash at the key corresponding to the message. If the
6
6
  # key does not exist, returns a NullObject instance.
7
7
  class Proxy
8
+ include Enumerable
8
9
  # The one and only NullObject instance
9
10
  NO_OBJECT = NullObject.new
10
11
 
@@ -24,21 +25,67 @@ module HashProxy
24
25
  @converted = {}
25
26
  end
26
27
 
27
- # The magic. Turns arbitrary method invocations into
28
+ # Returns the number of values stored in the underlying hash
29
+ #
30
+ # @return [Integer]
31
+ def size
32
+ @hash.size + @converted.size
33
+ end
34
+
35
+ # Yields to the provided block all the values in this Hash proxy. All values
36
+ # are converted via #convert_value as they are yielded. The order in which
37
+ # values are yielded is not deterministic. Insertion order in the original
38
+ # hash may be lost if some values are already converted.
39
+ def each(&blk)
40
+ enum = Enumerator.new do |y|
41
+ @converted.each {|k, v| y.yield(k,v) }
42
+ @hash.each {|k,v| y.yield(k, self.move_value(k)) }
43
+ end
44
+ if blk.nil?
45
+ enum
46
+ else
47
+ enum.each do |k,v|
48
+ blk.call(k,v)
49
+ end
50
+ end
51
+ end
52
+
53
+ # Returns the converted value in the original
54
+ # hash associated with the given key
55
+ #
56
+ # @param [Object] key The value to look up
57
+ # @return [Object] The object associated with the key
58
+ def [](key)
59
+ self.send(key)
60
+ end
61
+
62
+ # Sets a value after converting it to a Proxy if necessary
63
+ #
64
+ # @param [Object] key The key of the value to set
65
+ # @param [Object] value The value to set
66
+ def []=(key, value)
67
+ self.send("#{key}=", value)
68
+ end
69
+
70
+ # Turns arbitrary method invocations into
28
71
  # lookups or sets on the contained hash
29
72
  def method_missing(name, *args)
30
73
  name_str = name.to_s
31
74
  if name_str.end_with?(EQUALS)
32
- @converted[name_str[0..-2]] = convert_value(args.first)
75
+ # Handle edge case (self.send(:"=", 'foo') ? why would someone do this)
76
+ if name_str != EQUALS
77
+ @converted[name_str[0..-2].to_sym] = convert_value(args.first)
78
+ else
79
+ super
80
+ end
33
81
  else
34
- # Move the value from the original hash to the converted hash.
35
- # Support both symbol or string keys
36
- if @converted.has_key?(name_str)
37
- @converted[name_str]
82
+ # Return the value if it has already been converted
83
+ if @converted.has_key?(name)
84
+ @converted[name]
38
85
  else
39
- unconverted = @hash.delete(name) || @hash.delete(name_str)
40
- converted = convert_value(unconverted)
41
- @converted[name_str] = converted
86
+ # Move the value from the original hash to the converted hash.
87
+ # Support both symbol or string keys
88
+ self.move_value(name, name_str)
42
89
  end
43
90
  end
44
91
  end
@@ -80,5 +127,13 @@ module HashProxy
80
127
  value || NO_OBJECT
81
128
  end
82
129
  end
130
+
131
+ # moves a value from the original hash to the converted
132
+ # hash after converting the value to a proxy if necessary
133
+ def move_value(name, name_str = name.to_s)
134
+ @converted[name] = self.convert_value(@hash.delete(name) || @hash.delete(name_str))
135
+ end
136
+
83
137
  end
138
+
84
139
  end
@@ -2,6 +2,39 @@
2
2
  require File.expand_path('../spec_helper', __FILE__)
3
3
 
4
4
  describe HashProxy do
5
+ it "supports enumerable" do
6
+ hash = {foo: 'bar', baz: 'bip', smee: 'cree'}
7
+ proxy = HashProxy::Proxy.new(hash)
8
+ iterator = proxy.each
9
+ iterator.to_a.should eq([[:foo, 'bar'], [:baz, 'bip'], [:smee, 'cree']])
10
+
11
+ proxy.take(1).should eq([[:foo, 'bar']])
12
+ end
13
+
14
+ it "behaves kind of like a hash" do
15
+ hash = {foo: 'bar', baz: 'bip', smee: 'cree'}
16
+ proxy = HashProxy::Proxy.new(hash)
17
+ proxy.size.should eq(3)
18
+ proxy.each.to_a.size.should eq(3)
19
+ proxy.each.to_a.map{|a| a.first}.should eq([:foo, :baz, :smee])
20
+ proxy.each.to_a.map{|a| a.last}.should eq(['bar', 'bip', 'cree'])
21
+ proxy[:foo].should eq('bar')
22
+ end
23
+
24
+ it "can call setters" do
25
+ proxy = HashProxy::Proxy.new({})
26
+ proxy.foo = 'foo val'
27
+ proxy.bar = {:bip => :baz, :smoo => :smee}
28
+
29
+ proxy.size.should eq(2)
30
+ proxy[:bar].class.should eq(HashProxy::Proxy)
31
+ end
32
+
33
+ it "handles crappy method calls" do
34
+ proxy = HashProxy::Proxy.new({})
35
+ lambda { proxy.send(:'=', 'crap') }.should raise_error(NoMethodError)
36
+ end
37
+
5
38
  it "turns hash keys into method calls" do
6
39
  hash = {foo: 'bar', baz: 'bip'}
7
40
  proxy = HashProxy::Proxy.new(hash)
data/version.txt CHANGED
@@ -1 +1 @@
1
- 0.0.4
1
+ 0.1.0
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hash-proxy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-08 00:00:00.000000000 Z
12
+ date: 2012-06-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bones