sqlcached_client 0.0.2 → 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.
- checksums.yaml +4 -4
- data/lib/sqlcached_client/arel.rb +61 -0
- data/lib/sqlcached_client/entity.rb +57 -10
- data/lib/sqlcached_client/server.rb +3 -2
- data/lib/sqlcached_client/version.rb +1 -1
- data/spec/sqlcached_client/entity_spec.rb +18 -5
- data/spec/sqlcached_client/resultset_spec.rb +2 -3
- data/spec/sqlcached_client/server_spec.rb +3 -2
- data/sqlcached_client.gemspec +3 -0
- metadata +45 -5
- data/lib/sqlcached_client/hash_struct.rb +0 -70
- data/spec/sqlcached_client/hash_struct_spec.rb +0 -26
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 30b7e7df7003436bc67762203e5e3fdd982be9b9
|
|
4
|
+
data.tar.gz: e9fbb528788728392c7b5a6b879a38230beafd11
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 084112afa0b779ff0772ef3fcdbe43e12e3d5fbeea51dc7b177d5dfef29d0a3cf37cc9df665493d1c00450b96d77ed8fa77088ff74bf5999f539cdf4f33986ec
|
|
7
|
+
data.tar.gz: cd72f5a608e867d7defdcadfa37b42757bb022af05273d853cb472d343f1614bbfd117613bc1b2bbdb5a3f93e6d4a2ad6723d3edaaf0183d1ca3c4e4459b9a20
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require 'singleton'
|
|
2
|
+
require 'arel'
|
|
3
|
+
require 'active_record'
|
|
4
|
+
require 'nulldb'
|
|
5
|
+
|
|
6
|
+
module SqlcachedClient
|
|
7
|
+
module Arel
|
|
8
|
+
|
|
9
|
+
# Builds a SQL query executing the Arel statements in the given block.
|
|
10
|
+
# @param tables_map [Hash] in the form of
|
|
11
|
+
# { :t1 => [:par1, :par2], :t2 => :par3, :t3 => nil }
|
|
12
|
+
# @param arel_block [Proc]
|
|
13
|
+
# @return [Arel] an object that responds to 'to_sql'
|
|
14
|
+
def build_arel(tables_map, arel_block)
|
|
15
|
+
table_names = tables_map.keys
|
|
16
|
+
# attributes of this struct returns Arel tables named as the attribute
|
|
17
|
+
context = Struct.new(*table_names).new(
|
|
18
|
+
*table_names.map do |t_name|
|
|
19
|
+
ArelWrapper.arel_module::Table.new(t_name)
|
|
20
|
+
end
|
|
21
|
+
)
|
|
22
|
+
# build an Arel object evaluating the block if any
|
|
23
|
+
arel_q =
|
|
24
|
+
if arel_block
|
|
25
|
+
context.instance_eval(&arel_block)
|
|
26
|
+
else
|
|
27
|
+
# no block given, add the default SELECT *
|
|
28
|
+
context.send(tables_map.keys.first).project(
|
|
29
|
+
ArelWrapper.arel_module.sql('*'))
|
|
30
|
+
end
|
|
31
|
+
# add the 'where' conditions passed as parameters (values in tables_map)
|
|
32
|
+
tables_map.inject(arel_q) do |query_acc, item|
|
|
33
|
+
t_name, parameters = item
|
|
34
|
+
table = context.send(t_name)
|
|
35
|
+
parameters ||= []
|
|
36
|
+
parameters = [parameters] if !parameters.respond_to?(:inject)
|
|
37
|
+
parameters.inject(query_acc) do |arel, param|
|
|
38
|
+
arel.where(table[param].eq("{{ #{param} }}"))
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end # method build_arel
|
|
42
|
+
end # module Arel
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
class ArelWrapper
|
|
47
|
+
include Singleton
|
|
48
|
+
|
|
49
|
+
def initialize
|
|
50
|
+
::Arel::Table.engine = ::ActiveRecord::Base.establish_connection(
|
|
51
|
+
adapter: :nulldb)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
class << self
|
|
55
|
+
def arel_module
|
|
56
|
+
instance
|
|
57
|
+
::Arel
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end # class ArelWrapper
|
|
61
|
+
end
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
require 'sqlcached_client/hash_struct'
|
|
2
1
|
require 'sqlcached_client/resultset'
|
|
3
2
|
require 'sqlcached_client/server'
|
|
3
|
+
require 'sqlcached_client/arel'
|
|
4
4
|
|
|
5
5
|
module SqlcachedClient
|
|
6
|
-
class Entity
|
|
6
|
+
class Entity
|
|
7
|
+
extend Arel
|
|
7
8
|
|
|
8
|
-
attr_reader :
|
|
9
|
+
attr_reader :attributes
|
|
9
10
|
|
|
10
11
|
# @param attributes [Hash]
|
|
11
12
|
def initialize(attributes)
|
|
12
|
-
@
|
|
13
|
-
|
|
13
|
+
@attributes = attributes
|
|
14
|
+
self.class.define_readers(attributes.keys)
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
|
|
@@ -24,8 +25,22 @@ module SqlcachedClient
|
|
|
24
25
|
|
|
25
26
|
# Sets the query of this entity if a parameter is provided, otherwise
|
|
26
27
|
# returns the value previously set.
|
|
27
|
-
def query(
|
|
28
|
-
|
|
28
|
+
def query(*args, &block)
|
|
29
|
+
if args.empty?
|
|
30
|
+
@query
|
|
31
|
+
else
|
|
32
|
+
if args[0].is_a?(String)
|
|
33
|
+
@query = args[0].strip
|
|
34
|
+
else
|
|
35
|
+
@query = build_arel(
|
|
36
|
+
args.inject({}) do |acc, param|
|
|
37
|
+
acc.merge(
|
|
38
|
+
param.is_a?(Hash) ? param : Hash[ [[param, nil]] ]
|
|
39
|
+
)
|
|
40
|
+
end,
|
|
41
|
+
block).to_sql
|
|
42
|
+
end
|
|
43
|
+
end
|
|
29
44
|
end
|
|
30
45
|
|
|
31
46
|
# Configures the server of this entity if a parameter is provided,
|
|
@@ -56,7 +71,7 @@ module SqlcachedClient
|
|
|
56
71
|
# Runs the entity query with the provided parameters
|
|
57
72
|
# @return [Resultset]
|
|
58
73
|
def where(params, dry_run = false)
|
|
59
|
-
request = server.format_request(query_id, query, params)
|
|
74
|
+
request = server.format_request(query_id, query, params, cache)
|
|
60
75
|
if dry_run
|
|
61
76
|
request
|
|
62
77
|
else
|
|
@@ -143,6 +158,39 @@ module SqlcachedClient
|
|
|
143
158
|
@registered_associations || []
|
|
144
159
|
end
|
|
145
160
|
|
|
161
|
+
# Define the readers for the attribute names specified
|
|
162
|
+
# @param attr_names [Array]
|
|
163
|
+
def define_readers(attr_names)
|
|
164
|
+
if @_readers_defined.nil?
|
|
165
|
+
attr_names.each do |attr_name|
|
|
166
|
+
if method_defined?(attr_name)
|
|
167
|
+
raise "Cannot define accessor: #{attr_name}"
|
|
168
|
+
else
|
|
169
|
+
define_method(attr_name) do
|
|
170
|
+
attributes[attr_name]
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
@_readers_defined = true
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Configures the caching timing if a parameter is provided, otherwise
|
|
179
|
+
# returns the value set in the current class or in a superclass.
|
|
180
|
+
# Default value is true.
|
|
181
|
+
def cache(seconds = nil)
|
|
182
|
+
if seconds.nil?
|
|
183
|
+
@cache ||
|
|
184
|
+
if (superclass = ancestors[1]).respond_to?(:cache)
|
|
185
|
+
superclass.cache
|
|
186
|
+
else
|
|
187
|
+
true
|
|
188
|
+
end
|
|
189
|
+
else
|
|
190
|
+
@cache = seconds
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
146
194
|
private
|
|
147
195
|
|
|
148
196
|
def register_association(association_name)
|
|
@@ -174,8 +222,7 @@ module SqlcachedClient
|
|
|
174
222
|
end
|
|
175
223
|
|
|
176
224
|
def to_h
|
|
177
|
-
|
|
178
|
-
Hash[ attribute_names.map { |a_name| [a_name, send(a_name)] } ]
|
|
225
|
+
attributes
|
|
179
226
|
end
|
|
180
227
|
|
|
181
228
|
end # class Entity
|
|
@@ -50,11 +50,12 @@ module SqlcachedClient
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
def format_request(query_id, query_template, params)
|
|
53
|
+
def format_request(query_id, query_template, params, cache)
|
|
54
54
|
{
|
|
55
55
|
queryId: query_id,
|
|
56
56
|
queryTemplate: query_template,
|
|
57
|
-
queryParams: params
|
|
57
|
+
queryParams: params,
|
|
58
|
+
cache: cache
|
|
58
59
|
}
|
|
59
60
|
end
|
|
60
61
|
|
|
@@ -5,8 +5,16 @@ describe SqlcachedClient::Entity do
|
|
|
5
5
|
|
|
6
6
|
describe :initialize do
|
|
7
7
|
it "should record the attribute names" do
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
h = { foo: 'bar', baz: 'biz' }
|
|
9
|
+
e = Class.new(SqlcachedClient::Entity).new(h)
|
|
10
|
+
expect(e.attributes).to eq(h)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "should define readers methods named as attributes.keys" do
|
|
14
|
+
entity_class = Class.new(SqlcachedClient::Entity)
|
|
15
|
+
entity = entity_class.new(foo: 'bar', baz: 'biz')
|
|
16
|
+
expect(entity.foo).to eq('bar')
|
|
17
|
+
expect(entity.baz).to eq('biz')
|
|
10
18
|
end
|
|
11
19
|
end
|
|
12
20
|
|
|
@@ -93,7 +101,7 @@ describe SqlcachedClient::Entity do
|
|
|
93
101
|
context "if dry_run" do
|
|
94
102
|
it "should return the request that would be sent to the server" do
|
|
95
103
|
entity_class.server(double(format_request: "this is the request"))
|
|
96
|
-
expect(entity_class.server).to receive(:format_request).with("foo", "bar", { baz: "biz" })
|
|
104
|
+
expect(entity_class.server).to receive(:format_request).with("foo", "bar", { baz: "biz" }, true)
|
|
97
105
|
expect(entity_class.where({ baz: "biz" }, true)).to eq("this is the request")
|
|
98
106
|
end
|
|
99
107
|
end
|
|
@@ -106,7 +114,7 @@ describe SqlcachedClient::Entity do
|
|
|
106
114
|
session: [[{ key: "value" }], 2, 3]
|
|
107
115
|
))
|
|
108
116
|
expect(entity_class.server).to receive(:format_request).with(
|
|
109
|
-
"foo", "bar", { baz: "biz" })
|
|
117
|
+
"foo", "bar", { baz: "biz" }, true)
|
|
110
118
|
expect(entity_class.where({ baz: "biz" })).to be_instance_of(
|
|
111
119
|
SqlcachedClient::Resultset)
|
|
112
120
|
end
|
|
@@ -145,6 +153,11 @@ describe SqlcachedClient::Entity do
|
|
|
145
153
|
|
|
146
154
|
|
|
147
155
|
describe :to_h do
|
|
148
|
-
|
|
156
|
+
it "should return attributes" do
|
|
157
|
+
entity_class = Class.new(SqlcachedClient::Entity)
|
|
158
|
+
h = { foo: 'bar', baz: 'biz' }
|
|
159
|
+
entity = entity_class.new(h)
|
|
160
|
+
expect(entity.to_h).to eq(h)
|
|
161
|
+
end
|
|
149
162
|
end
|
|
150
163
|
end
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
require 'sqlcached_client/resultset'
|
|
2
|
-
require 'sqlcached_client/hash_struct'
|
|
3
2
|
|
|
4
3
|
describe SqlcachedClient::Resultset do
|
|
5
4
|
|
|
@@ -12,9 +11,9 @@ describe SqlcachedClient::Resultset do
|
|
|
12
11
|
|
|
13
12
|
context "when passed entities are hashes" do
|
|
14
13
|
it "should map them to instances of the entity class provided" do
|
|
15
|
-
r = SqlcachedClient::Resultset.new(SqlcachedClient::
|
|
14
|
+
r = SqlcachedClient::Resultset.new(SqlcachedClient::Entity,
|
|
16
15
|
[{ foo: 'bar' }] * 3)
|
|
17
|
-
expect(r.entities[0]).to be_instance_of(SqlcachedClient::
|
|
16
|
+
expect(r.entities[0]).to be_instance_of(SqlcachedClient::Entity)
|
|
18
17
|
end
|
|
19
18
|
end
|
|
20
19
|
|
|
@@ -22,10 +22,11 @@ describe SqlcachedClient::Server do
|
|
|
22
22
|
|
|
23
23
|
describe :format_request do
|
|
24
24
|
it "should be an hash with id, template, params keys" do
|
|
25
|
-
expect(server.format_request("foo", "bar", "baz")).to eq({
|
|
25
|
+
expect(server.format_request("foo", "bar", "baz", "cache")).to eq({
|
|
26
26
|
queryId: "foo",
|
|
27
27
|
queryTemplate: "bar",
|
|
28
|
-
queryParams: "baz"
|
|
28
|
+
queryParams: "baz",
|
|
29
|
+
cache: "cache"
|
|
29
30
|
})
|
|
30
31
|
end
|
|
31
32
|
end
|
data/sqlcached_client.gemspec
CHANGED
|
@@ -19,6 +19,9 @@ Gem::Specification.new do |spec|
|
|
|
19
19
|
spec.require_paths = ["lib"]
|
|
20
20
|
|
|
21
21
|
spec.add_dependency "activesupport", "~> 4.2"
|
|
22
|
+
spec.add_dependency "arel", "~> 6.0"
|
|
23
|
+
spec.add_dependency "activerecord", "~> 4.2"
|
|
24
|
+
spec.add_dependency "activerecord-nulldb-adapter", "~> 0.3"
|
|
22
25
|
|
|
23
26
|
spec.add_development_dependency "bundler", "~> 1.6"
|
|
24
27
|
spec.add_development_dependency "rake"
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sqlcached_client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 0.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Roberto Maestroni
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2015-05-
|
|
11
|
+
date: 2015-05-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -24,6 +24,48 @@ dependencies:
|
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '4.2'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: arel
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '6.0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '6.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: activerecord
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '4.2'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '4.2'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: activerecord-nulldb-adapter
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0.3'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0.3'
|
|
27
69
|
- !ruby/object:Gem::Dependency
|
|
28
70
|
name: bundler
|
|
29
71
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -79,13 +121,12 @@ files:
|
|
|
79
121
|
- README.md
|
|
80
122
|
- Rakefile
|
|
81
123
|
- lib/sqlcached_client.rb
|
|
124
|
+
- lib/sqlcached_client/arel.rb
|
|
82
125
|
- lib/sqlcached_client/entity.rb
|
|
83
|
-
- lib/sqlcached_client/hash_struct.rb
|
|
84
126
|
- lib/sqlcached_client/resultset.rb
|
|
85
127
|
- lib/sqlcached_client/server.rb
|
|
86
128
|
- lib/sqlcached_client/version.rb
|
|
87
129
|
- spec/sqlcached_client/entity_spec.rb
|
|
88
|
-
- spec/sqlcached_client/hash_struct_spec.rb
|
|
89
130
|
- spec/sqlcached_client/resultset_spec.rb
|
|
90
131
|
- spec/sqlcached_client/server_spec.rb
|
|
91
132
|
- sqlcached_client.gemspec
|
|
@@ -115,6 +156,5 @@ specification_version: 4
|
|
|
115
156
|
summary: A Ruby client for sqlcached
|
|
116
157
|
test_files:
|
|
117
158
|
- spec/sqlcached_client/entity_spec.rb
|
|
118
|
-
- spec/sqlcached_client/hash_struct_spec.rb
|
|
119
159
|
- spec/sqlcached_client/resultset_spec.rb
|
|
120
160
|
- spec/sqlcached_client/server_spec.rb
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
module SqlcachedClient
|
|
2
|
-
# Maps recursively hashes into objects with lazy evaluation. For example
|
|
3
|
-
#
|
|
4
|
-
# hs = HashStruct.new({
|
|
5
|
-
# a: ['foo', { a1: [{ a2: 'one' }, 'two', 'three'] }, 'bar'],
|
|
6
|
-
# b: 'baz',
|
|
7
|
-
# c: 4,
|
|
8
|
-
# d: { d1: { d2: { d3: 'hi' } } }
|
|
9
|
-
# })
|
|
10
|
-
# # => #<HashStruct:0x0000000f188008>
|
|
11
|
-
#
|
|
12
|
-
# hs.b
|
|
13
|
-
# # => "baz"
|
|
14
|
-
#
|
|
15
|
-
# hs.c
|
|
16
|
-
# # => 4
|
|
17
|
-
#
|
|
18
|
-
# hs.a
|
|
19
|
-
# # => ["foo", #<HashStruct:0x0000000f1dc798>, "bar"]
|
|
20
|
-
#
|
|
21
|
-
# hs.a[1].a1
|
|
22
|
-
# # => [#<HashStruct:0x0000000f275ce0>, "two", "three"]
|
|
23
|
-
#
|
|
24
|
-
# hs.a[1].a1[0].a2
|
|
25
|
-
# # => "one"
|
|
26
|
-
#
|
|
27
|
-
# # values are memoized
|
|
28
|
-
# hs
|
|
29
|
-
# # => #<HashStruct:0x0000000f188008
|
|
30
|
-
# # @_a=["foo", #<HashStruct:0x0000000f1dc798 @_a1=[#<HashStruct:0x0000000f275ce0 @_a2="one">, "two", "three"]>, "bar"],
|
|
31
|
-
# # @_b="baz",
|
|
32
|
-
# # @_c=4>
|
|
33
|
-
class HashStruct
|
|
34
|
-
|
|
35
|
-
def initialize(hash)
|
|
36
|
-
hash.each do |key, value|
|
|
37
|
-
define_singleton_method(key.to_sym, &HashStruct.build(value, key))
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
class << self
|
|
42
|
-
|
|
43
|
-
# @return [Proc]
|
|
44
|
-
def build(value, accessor_name = nil)
|
|
45
|
-
lambda =
|
|
46
|
-
if value.is_a?(Hash)
|
|
47
|
-
-> (aself, value) { HashStruct.new(value) }
|
|
48
|
-
elsif value.is_a?(Array)
|
|
49
|
-
-> (aself, value) {
|
|
50
|
-
value.map { |item| aself.instance_eval(&HashStruct.build(item)) }
|
|
51
|
-
}
|
|
52
|
-
else
|
|
53
|
-
-> (aself, value) { value }
|
|
54
|
-
end
|
|
55
|
-
if !accessor_name.nil?
|
|
56
|
-
memoize_v = "@_#{accessor_name}"
|
|
57
|
-
Proc.new {
|
|
58
|
-
if instance_variable_defined?(memoize_v)
|
|
59
|
-
instance_variable_get(memoize_v)
|
|
60
|
-
else
|
|
61
|
-
instance_variable_set(memoize_v, lambda.call(self, value))
|
|
62
|
-
end
|
|
63
|
-
}
|
|
64
|
-
else
|
|
65
|
-
Proc.new { lambda.call(self, value) }
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end # class << self
|
|
69
|
-
end # class HashStruct
|
|
70
|
-
end
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
require 'sqlcached_client/hash_struct'
|
|
2
|
-
|
|
3
|
-
RSpec.describe SqlcachedClient::HashStruct do
|
|
4
|
-
let(:hash_struct) do
|
|
5
|
-
SqlcachedClient::HashStruct.new({
|
|
6
|
-
a: ['foo', { a1: [{ a2: 'one' }, 'two', 'three'] }, 'bar'],
|
|
7
|
-
b: 'baz',
|
|
8
|
-
c: 4,
|
|
9
|
-
d: { d1: { d2: { d3: 'hi' } } }
|
|
10
|
-
})
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
it "should map keys into methods" do
|
|
14
|
-
[:a, :b, :c, :d].each do |m|
|
|
15
|
-
expect(hash_struct.respond_to?(m)).to eq(true)
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
it "should map recoursively" do
|
|
20
|
-
ary = hash_struct.a
|
|
21
|
-
expect(ary[0]).to eq('foo')
|
|
22
|
-
expect(ary[1].a1[0].a2).to eq('one')
|
|
23
|
-
expect(hash_struct.d.d1.d2.d3).to eq('hi')
|
|
24
|
-
expect(hash_struct.c).to eq(4)
|
|
25
|
-
end
|
|
26
|
-
end
|