metahash-rb 1.1.0 → 1.1.2
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.
- checksums.yaml +4 -4
- data/README.md +12 -7
- data/lib/metahash/metaclass.rb +24 -22
- data/lib/metahash/metadata.rb +14 -8
- data/lib/metahash/version.rb +1 -1
- data/spec/hash_spec.rb +8 -1
- data/spec/metadata_spec.rb +64 -25
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b21c51283eacfaf1a20c154f7999eb8843e310e6
|
4
|
+
data.tar.gz: a9e649da99e7b72785265b348d1534907bd74262
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c36be5a77381a5bcab17dc5bf313c35ddfb239ef67b27f00358d530cf4f2dc38722bd54db466f859dc906cc2616b4ee1d9b3414a6f7bb0f306394e6a6c042966
|
7
|
+
data.tar.gz: 007622bcea83aea25e888c798885333ae35d1af3c50bb315f1665cc3a42552f2aa57f7da49607ab84a81e554286b162b8e56dabb49f6297c8d4b955fd3a12111
|
data/README.md
CHANGED
@@ -17,9 +17,9 @@ Provides a subclass of Hash and a wrapper around Rails' serialize attribute for
|
|
17
17
|
Arand new Metadata objects act just like hashes:
|
18
18
|
|
19
19
|
h = Metadata.new
|
20
|
-
h
|
20
|
+
h
|
21
21
|
=> {}
|
22
|
-
|
22
|
+
|
23
23
|
Accessing nested data requires no wrapping conditions checking for existence of the rquested data:
|
24
24
|
|
25
25
|
h.outer.inner
|
@@ -29,18 +29,23 @@ Possible real-word example:
|
|
29
29
|
|
30
30
|
if (min_numbers = h.password_rules.formats.numbers.minimum).present?
|
31
31
|
# some code using min_numbers
|
32
|
-
else
|
32
|
+
else
|
33
33
|
# data doesn't exist in h
|
34
|
-
|
34
|
+
|
35
35
|
h.password_rules.formats.numbers.minimum = 1
|
36
|
-
# h
|
36
|
+
# h
|
37
37
|
# => { password_rules: { formats: { numbers: { minimum: 1 } } } }
|
38
38
|
end
|
39
39
|
|
40
|
+
Convert an existing hash to metadata
|
41
|
+
|
42
|
+
{a: 1}.to_metadata.a
|
43
|
+
# => 1
|
44
|
+
|
40
45
|
#### Access to values stored in nested hashes via method call syntax
|
41
46
|
|
42
47
|
h = Metadata.new( { outer: { inner: { hash_key: "value" } } } )
|
43
|
-
|
48
|
+
|
44
49
|
h.outer.inner.hash_key
|
45
50
|
=> "value"
|
46
51
|
|
@@ -49,7 +54,7 @@ Possible real-word example:
|
|
49
54
|
h = Metadata.new
|
50
55
|
h
|
51
56
|
=> {}
|
52
|
-
|
57
|
+
|
53
58
|
h.outer.inner = 2
|
54
59
|
h
|
55
60
|
=> { outer: { inner: 2 } }
|
data/lib/metahash/metaclass.rb
CHANGED
@@ -2,30 +2,32 @@
|
|
2
2
|
# allows the adding of methods to instances,
|
3
3
|
# but not the entire set of instances for a
|
4
4
|
# particular class
|
5
|
-
module
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
self
|
5
|
+
module MetaHash
|
6
|
+
module Metaclass
|
7
|
+
# The hidden singleton lurks behind everyone
|
8
|
+
def metaclass
|
9
|
+
class << self
|
10
|
+
self
|
11
|
+
end
|
10
12
|
end
|
11
|
-
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
def meta_eval(&block)
|
15
|
+
metaclass.instance_eval(&block)
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
# Adds methods to a metaclass
|
19
|
+
def meta_def(name, &block)
|
20
|
+
meta_eval {
|
21
|
+
define_method(name, &block)
|
22
|
+
}
|
23
|
+
end
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
25
|
+
# unused
|
26
|
+
# Defines an instance method within a class
|
27
|
+
# def class_def(name, &block)
|
28
|
+
# class_eval {
|
29
|
+
# define_method(name, &block)
|
30
|
+
# }
|
31
|
+
# end
|
32
|
+
end
|
31
33
|
end
|
data/lib/metahash/metadata.rb
CHANGED
@@ -20,7 +20,7 @@
|
|
20
20
|
# h[:inner][:key] == "value"
|
21
21
|
#
|
22
22
|
class Metadata < Hash
|
23
|
-
include Metaclass
|
23
|
+
include MetaHash::Metaclass
|
24
24
|
# in the event we are overriding a method, have a way to
|
25
25
|
# get back to the original
|
26
26
|
METHOD_BACKUP_KEY = "metadata_original_"
|
@@ -67,14 +67,12 @@ class Metadata < Hash
|
|
67
67
|
# @raise [ArgumentError] if one of the keys is method of Hash
|
68
68
|
def method_missing(method_name, *args)
|
69
69
|
# check for assignment
|
70
|
-
if
|
71
|
-
|
72
|
-
|
73
|
-
assign_value(key, args[0])
|
70
|
+
if method_name.to_s[-1] == "="
|
71
|
+
assign_value(method_name, args[0])
|
74
72
|
else
|
75
73
|
value = self[method_name]
|
76
|
-
if
|
77
|
-
@empty_nested_hashes << method_name
|
74
|
+
if value.nil?
|
75
|
+
@empty_nested_hashes << method_name
|
78
76
|
value = self
|
79
77
|
end
|
80
78
|
value
|
@@ -84,19 +82,23 @@ class Metadata < Hash
|
|
84
82
|
|
85
83
|
# Metdata has indifferent access
|
86
84
|
def [](key)
|
85
|
+
# self.send(key)
|
87
86
|
super(key.to_sym)
|
88
87
|
end
|
89
88
|
|
90
89
|
# # Metadata has indifferent access,
|
91
90
|
# # so just say that all the keys are symbols.
|
92
91
|
def []=(key, value)
|
92
|
+
if value.is_a?(Hash) && !value.is_a?(Metadata)
|
93
|
+
value = Metadata.new(value)
|
94
|
+
end
|
93
95
|
super(key.to_sym, value)
|
94
96
|
end
|
95
97
|
|
96
98
|
# tests the ability to use this key as a key in a hash
|
97
99
|
# @param [Symbol] key
|
98
100
|
# @return [Boolean] whether or not this can be used as a hash key
|
99
|
-
def
|
101
|
+
def key_not_in_use?(key)
|
100
102
|
not self.respond_to?(key)
|
101
103
|
end
|
102
104
|
|
@@ -126,9 +128,13 @@ class Metadata < Hash
|
|
126
128
|
|
127
129
|
private
|
128
130
|
|
131
|
+
# @param [Symbol] key "field_name=""
|
129
132
|
def assign_value(key, value)
|
133
|
+
key = key.to_s.chop
|
130
134
|
deepest_metadata = self
|
131
135
|
|
136
|
+
value = Metadata.new(value) if value.is_a?(Hash)
|
137
|
+
|
132
138
|
if not @empty_nested_hashes.empty?
|
133
139
|
@empty_nested_hashes.each do |key|
|
134
140
|
deepest_metadata = deepest_metadata[key] = Metadata.new
|
data/lib/metahash/version.rb
CHANGED
data/spec/hash_spec.rb
CHANGED
@@ -4,6 +4,13 @@ describe Hash do
|
|
4
4
|
context "to_metadata" do
|
5
5
|
subject(:h){ { a: 1 }.to_metadata }
|
6
6
|
|
7
|
-
it
|
7
|
+
it "is a Metadata" do
|
8
|
+
expect(h).to be_a Metadata
|
9
|
+
end
|
10
|
+
|
11
|
+
it "behaves like a Metdata" do
|
12
|
+
expect(h.a).to eq 1
|
13
|
+
end
|
8
14
|
end
|
15
|
+
|
9
16
|
end
|
data/spec/metadata_spec.rb
CHANGED
@@ -33,16 +33,21 @@ describe Metadata do
|
|
33
33
|
expect(m["b"]).to eq 2
|
34
34
|
end
|
35
35
|
|
36
|
+
it "converts a hash to metadata" do
|
37
|
+
m[:h] = { a: 2 }
|
38
|
+
expect(m.h).to be_a Metadata
|
39
|
+
end
|
40
|
+
|
36
41
|
end
|
37
42
|
|
38
|
-
describe "
|
43
|
+
describe "key_not_in_use?" do
|
39
44
|
|
40
45
|
it "is true for keys that aren't methods" do
|
41
|
-
expect(m.
|
46
|
+
expect(m.key_not_in_use?(:b)).to eq true
|
42
47
|
end
|
43
48
|
|
44
49
|
it "is false for existing methods" do
|
45
|
-
expect(m.
|
50
|
+
expect(m.key_not_in_use?(:to_hash)).to eq false
|
46
51
|
end
|
47
52
|
end
|
48
53
|
|
@@ -122,35 +127,69 @@ describe Metadata do
|
|
122
127
|
context "assigns values" do
|
123
128
|
let(:m){Metadata.new}
|
124
129
|
|
125
|
-
it "sets a non-exsiting deep value" do
|
126
|
-
m.a.b = 2
|
127
|
-
expect(m.a.b).to eq 2
|
128
|
-
end
|
129
130
|
|
130
|
-
it "
|
131
|
-
m.a
|
132
|
-
m
|
133
|
-
expect(m.a
|
134
|
-
expect(m.a.max).to eq 3
|
131
|
+
it "allows multiple ways of assigning the same key" do
|
132
|
+
m.a = "1"
|
133
|
+
m[:a] = "2"
|
134
|
+
expect(m.a).to eq "1"
|
135
135
|
end
|
136
136
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
137
|
+
context "via attribute assignment style" do
|
138
|
+
it "sets a non-exsiting deep value" do
|
139
|
+
m.a.b = 2
|
140
|
+
expect(m.a.b).to eq 2
|
141
|
+
end
|
141
142
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
143
|
+
it "sets with specific keys" do
|
144
|
+
m.a.min = 2
|
145
|
+
m.a.max = 3
|
146
|
+
expect(m.a.min).to eq 2
|
147
|
+
expect(m.a.max).to eq 3
|
148
|
+
end
|
149
|
+
|
150
|
+
it "overrides existing methods if set" do
|
151
|
+
m.keys = 2
|
152
|
+
expect(m.keys).to eq 2
|
153
|
+
end
|
154
|
+
|
155
|
+
it "overrides existing methods if set to non-simple objects" do
|
156
|
+
m.a.b = 2
|
157
|
+
m.a.keys = 3
|
158
|
+
expect(m.a.keys).to eq 3
|
159
|
+
end
|
160
|
+
|
161
|
+
it "can overrid min and max of deeply nested hashes" do
|
162
|
+
m.password_rules.formats.digits.max = 3
|
163
|
+
m.password_rules.formats.digits.min = 2
|
164
|
+
|
165
|
+
expect(m.password_rules.formats.digits.min).to eq 2
|
166
|
+
expect(m.password_rules.formats.digits.max).to eq 3
|
167
|
+
end
|
168
|
+
|
169
|
+
it "handles falsy values" do
|
170
|
+
m.a = false
|
171
|
+
expect(m.a).to eq false
|
172
|
+
end
|
173
|
+
|
174
|
+
it "converts hashes to metadata" do
|
175
|
+
m.a = { sub: 2 }
|
176
|
+
expect(m.a.sub).to eq 2
|
177
|
+
end
|
146
178
|
end
|
147
179
|
|
148
|
-
|
149
|
-
|
150
|
-
|
180
|
+
context "via hash style" do
|
181
|
+
it "handels falsy values" do
|
182
|
+
m[:a] = false
|
183
|
+
expect(m[:a]).to eq false
|
184
|
+
expect(m.a).to eq false
|
185
|
+
end
|
151
186
|
|
152
|
-
|
153
|
-
|
187
|
+
it "sets a non-existing deep value" do
|
188
|
+
pending "not yet supported"
|
189
|
+
m[:a][:b] = 2
|
190
|
+
expect(m[:a][:b]).to eq 2
|
191
|
+
expect(m.a.b).to eq 2
|
192
|
+
end
|
154
193
|
end
|
155
194
|
end
|
156
195
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: metahash-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- L. Preston Sego III
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-09-
|
11
|
+
date: 2014-09-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -144,7 +144,7 @@ rubyforge_project:
|
|
144
144
|
rubygems_version: 2.4.1
|
145
145
|
signing_key:
|
146
146
|
specification_version: 4
|
147
|
-
summary: MetaHash-1.1.
|
147
|
+
summary: MetaHash-1.1.2
|
148
148
|
test_files:
|
149
149
|
- spec/hash_spec.rb
|
150
150
|
- spec/metadata_spec.rb
|