hash-proxy 0.0.4 → 0.1.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/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