sd_struct 0.1.0 → 0.1.1
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 +20 -7
- data/lib/sd_struct/base.rb +47 -25
- data/lib/sd_struct/deep_search.rb +11 -4
- data/lib/sd_struct/version.rb +1 -1
- data/sd_struct.gemspec +1 -0
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b7a67f6e73b67288c75959f12b9c28557326ef7
|
4
|
+
data.tar.gz: 0e4dc23fda1637c672516f58aad9e79e8492b1b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1ac85d00a9d591074e27c9174cfb100cbdb220752060b8f811bf5c0d71d4acb357f91eef2bd7f6480c8b8529be51720898dd1e2d055b430d0be6a935fffa35c6
|
7
|
+
data.tar.gz: 58fa6f524bde91f41511e78d561eb829e746d8564965c136bf91c8462b5c4cdd835889a79894e4b41b43a00fdfc8f86a568affdb63dfc7d250d478de415bd2a6
|
data/README.md
CHANGED
@@ -71,13 +71,13 @@ sd_struct.to_h
|
|
71
71
|
```
|
72
72
|
|
73
73
|
|
74
|
-
> OpenStruct
|
75
|
-
>
|
74
|
+
> OpenStruct allows creation of a new field with dot notation while SDStruct
|
75
|
+
> prevents it
|
76
76
|
|
77
|
-
SDStruct
|
78
|
-
|
79
|
-
|
80
|
-
|
77
|
+
SDStruct disallows creation of a new field using dot notation to prevent
|
78
|
+
assigning unintended field when you mistyped the key/field. SDStruct is
|
79
|
+
stricter in that way. However, SDStruct can also be lenient. You can use square
|
80
|
+
brackets when you want to assign a new field.
|
81
81
|
|
82
82
|
```ruby
|
83
83
|
## OpenStruct
|
@@ -114,10 +114,10 @@ sd_struct.find('/array/0/one')
|
|
114
114
|
sd_struct.find('object->a', separator: '->')
|
115
115
|
# => "bau bau"
|
116
116
|
|
117
|
+
# You can push it to find deeper. It will return the first occurrence of the matched field
|
117
118
|
sd_struct.find('.array..one', separator: '.')
|
118
119
|
# => 1
|
119
120
|
|
120
|
-
# You can push it to find deeper. It will return the first occurrence of the matched field
|
121
121
|
sd_struct.find('//a')
|
122
122
|
# => "bau bau"
|
123
123
|
|
@@ -274,6 +274,19 @@ that doesn't have deep search and deep convert capabilities.
|
|
274
274
|
require 'sd_struct/base'
|
275
275
|
```
|
276
276
|
|
277
|
+
## Attribution
|
278
|
+
|
279
|
+
OpenStruct is used as the base of this project.
|
280
|
+
|
281
|
+
|
282
|
+
## TODO
|
283
|
+
|
284
|
+
* Add specs
|
285
|
+
* Add `method_missing` to define singleton method when a field/member/key is
|
286
|
+
called (and not during initialization) to execute initialization faster
|
287
|
+
* Reimplement SDStruct to extend Hash (possibly will make it faster)
|
288
|
+
|
289
|
+
|
277
290
|
## Contributing
|
278
291
|
|
279
292
|
1. Fork it ( https://github.com/styd/sd_struct/fork )
|
data/lib/sd_struct/base.rb
CHANGED
@@ -6,7 +6,7 @@ class SDStruct
|
|
6
6
|
using Module.new {
|
7
7
|
refine Hash do
|
8
8
|
#
|
9
|
-
#
|
9
|
+
# Changes current Hash object to SDStruct object
|
10
10
|
#
|
11
11
|
# @return [SDStruct] SDStruct object
|
12
12
|
#
|
@@ -16,9 +16,8 @@ class SDStruct
|
|
16
16
|
end
|
17
17
|
|
18
18
|
refine Array do
|
19
|
-
|
20
19
|
#
|
21
|
-
#
|
20
|
+
# Calls `to_struct` to an Array to go deeper or to a Hash to change it to SDStruct
|
22
21
|
#
|
23
22
|
# @return [Array<SDStruct,Object>] array of SDStruct or any other objects
|
24
23
|
#
|
@@ -42,18 +41,23 @@ class SDStruct
|
|
42
41
|
#
|
43
42
|
# p data # -> #<SDStruct .name="Matz", ['coding language']=:ruby, .age="old">
|
44
43
|
#
|
45
|
-
def initialize(hash = nil,
|
46
|
-
|
44
|
+
def initialize(hash = nil, opts = {})
|
45
|
+
opts = {
|
46
|
+
deep: true,
|
47
|
+
symbolize_keys: true
|
48
|
+
}.merge(opts)
|
49
|
+
|
50
|
+
@deep = opts[:deep]
|
47
51
|
@table = {}
|
48
52
|
if hash
|
49
53
|
hash.each_pair do |k, v|
|
50
|
-
@table[
|
54
|
+
@table[naturalize(k)] = structurize(v) # @deep is used in this method
|
51
55
|
end
|
52
56
|
end
|
53
57
|
end
|
54
58
|
|
55
59
|
#
|
56
|
-
#
|
60
|
+
# Duplicates an SDStruct object members.
|
57
61
|
#
|
58
62
|
def initialize_copy(orig)
|
59
63
|
super
|
@@ -92,7 +96,6 @@ class SDStruct
|
|
92
96
|
# Used internally to define field properties
|
93
97
|
#
|
94
98
|
def new_struct_member(name)
|
95
|
-
name = name.to_s.underscore.to_sym unless name[/^[A-Z]|\s+/]
|
96
99
|
unless respond_to?(name)
|
97
100
|
define_singleton_method(name) { @table[name] }
|
98
101
|
define_singleton_method("#{name}=") { |x| @table[name] = x }
|
@@ -100,14 +103,22 @@ class SDStruct
|
|
100
103
|
name
|
101
104
|
end
|
102
105
|
|
106
|
+
def naturalize(key)
|
107
|
+
unless key[/^[A-Z]|\s+/]
|
108
|
+
key.to_s.underscore.to_sym
|
109
|
+
else
|
110
|
+
key
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
103
114
|
#
|
104
|
-
#
|
115
|
+
# Calls to struct to a value if it is an Array or a Hash and @deep is true
|
105
116
|
#
|
106
117
|
def structurize(value)
|
107
118
|
( @deep && (value.is_a?(Hash) || value.is_a?(Array)) ) ? value.to_struct : value
|
108
119
|
end
|
109
120
|
|
110
|
-
protected :new_struct_member, :structurize
|
121
|
+
protected :new_struct_member, :naturalize, :structurize
|
111
122
|
|
112
123
|
|
113
124
|
#
|
@@ -117,7 +128,7 @@ class SDStruct
|
|
117
128
|
# person[:lang] # => ruby, same as person.lang
|
118
129
|
#
|
119
130
|
def [](name)
|
120
|
-
@table
|
131
|
+
@table[name] || @table[naturalize(name)]
|
121
132
|
end
|
122
133
|
|
123
134
|
#
|
@@ -128,21 +139,19 @@ class SDStruct
|
|
128
139
|
# person.lang # => ruby
|
129
140
|
#
|
130
141
|
def []=(name, value)
|
131
|
-
unless self
|
142
|
+
unless self[name].nil? || value.is_a?(self[name].class)
|
132
143
|
warn("You're assigning a value with different type as the previous value.")
|
133
144
|
end
|
134
|
-
@table[new_struct_member(name)] = structurize(value)
|
145
|
+
@table[new_struct_member(naturalize(name))] = structurize(value)
|
135
146
|
end
|
136
147
|
|
137
|
-
InspectKey = :__inspect_key__ # :nodoc:
|
138
|
-
|
139
148
|
#
|
140
149
|
# Returns a string containing a detailed summary of the keys and values.
|
141
150
|
#
|
142
151
|
def inspect
|
143
152
|
str = "#<#{self.class}"
|
144
153
|
|
145
|
-
ids = (Thread.current[
|
154
|
+
ids = (Thread.current[:sd_struct] ||= [])
|
146
155
|
if ids.include?(object_id)
|
147
156
|
return str << ' ...>'
|
148
157
|
end
|
@@ -181,7 +190,7 @@ class SDStruct
|
|
181
190
|
end
|
182
191
|
|
183
192
|
#
|
184
|
-
#
|
193
|
+
# Computes a hash-code for this SDStruct.
|
185
194
|
# Two hashes with the same content will have the same hash code
|
186
195
|
# (and will be eql?).
|
187
196
|
#
|
@@ -190,14 +199,14 @@ class SDStruct
|
|
190
199
|
end
|
191
200
|
|
192
201
|
#
|
193
|
-
#
|
202
|
+
# Exposes keys with space(s)
|
194
203
|
#
|
195
204
|
def spaced_keys
|
196
205
|
@table.keys - non_spaced_keys
|
197
206
|
end
|
198
207
|
|
199
208
|
#
|
200
|
-
#
|
209
|
+
# Exposes keys without space(s)
|
201
210
|
#
|
202
211
|
def non_spaced_keys
|
203
212
|
methods(false).select{|x| x[/^\S+[^=]$/]}
|
@@ -205,21 +214,34 @@ class SDStruct
|
|
205
214
|
alias :fields :non_spaced_keys
|
206
215
|
|
207
216
|
#
|
208
|
-
#
|
217
|
+
# Exposes all keys
|
209
218
|
#
|
210
219
|
def keys
|
211
220
|
@table.keys
|
212
221
|
end
|
213
222
|
|
214
223
|
#
|
215
|
-
#
|
224
|
+
# Deletes specified field or key
|
216
225
|
#
|
217
226
|
def delete_field(name)
|
218
|
-
|
219
|
-
@table.delete(
|
220
|
-
raise NameError.new("no field `#{
|
227
|
+
name = @table.has_key?(name) ? name : naturalize(name)
|
228
|
+
@table.delete(name) do
|
229
|
+
raise NameError.new("no field `#{name}' in #{self}", name)
|
221
230
|
end
|
222
|
-
singleton_class.__send__(:remove_method,
|
231
|
+
singleton_class.__send__(:remove_method, name, "#{name}=")
|
223
232
|
end
|
224
233
|
alias :delete_key :delete_field
|
234
|
+
|
235
|
+
def method_missing(m_id, *args)
|
236
|
+
m_nat = naturalize(m_id)
|
237
|
+
if args.length.zero?
|
238
|
+
if @table.key?(m_nat)
|
239
|
+
@table[new_struct_member(m_nat)]
|
240
|
+
end
|
241
|
+
else
|
242
|
+
err = NoMethodError.new "undefined method `#{m_id}' for #{self}", m_id, args
|
243
|
+
err.set_backtrace caller(1)
|
244
|
+
raise err
|
245
|
+
end
|
246
|
+
end
|
225
247
|
end
|
@@ -3,7 +3,7 @@ class SDStruct
|
|
3
3
|
refine Array do
|
4
4
|
|
5
5
|
#
|
6
|
-
#
|
6
|
+
# Digs deep into array until non-Array and non-Hash primitive data is found
|
7
7
|
#
|
8
8
|
# @param [Symbol] multiple symbols
|
9
9
|
# @return [String,Integer,Float,Boolean,nil] first matched result
|
@@ -32,7 +32,7 @@ class SDStruct
|
|
32
32
|
}
|
33
33
|
|
34
34
|
#
|
35
|
-
#
|
35
|
+
# Digs deep into Hash until non-Array and non-Hash primitive data is found
|
36
36
|
#
|
37
37
|
# @param [Symbol] multiple symbols
|
38
38
|
# @return [SDStruct,Hash,Array,String,Integer,Float,Boolean,nil] first matched result
|
@@ -60,7 +60,7 @@ class SDStruct
|
|
60
60
|
end
|
61
61
|
|
62
62
|
#
|
63
|
-
#
|
63
|
+
# Digs the content of @table which is a hash
|
64
64
|
#
|
65
65
|
# @param [Symbol] multiple symbols
|
66
66
|
# @return [SDStruct,Hash,Array,String,Integer,Float,Boolean,nil] first matched result
|
@@ -69,6 +69,13 @@ class SDStruct
|
|
69
69
|
@table.dig(*args)
|
70
70
|
end
|
71
71
|
|
72
|
+
#
|
73
|
+
# Finds value with keys specified like xpath
|
74
|
+
#
|
75
|
+
# @param [String] key string
|
76
|
+
# @param [Hash] option Hash
|
77
|
+
# @return [SDStruct,Hash,Array,String,Integer,Float,Boolean,nil] first matched result
|
78
|
+
#
|
72
79
|
def find(key_str, opts = {})
|
73
80
|
opts = {
|
74
81
|
separator: "/"
|
@@ -86,7 +93,7 @@ class SDStruct
|
|
86
93
|
if !!x[/\A[-+]?\d+\z/]
|
87
94
|
x.to_i
|
88
95
|
else
|
89
|
-
if x[
|
96
|
+
if x[/^$|^[A-Z]|\s+/]
|
90
97
|
x
|
91
98
|
else
|
92
99
|
x.underscore.to_sym
|
data/lib/sd_struct/version.rb
CHANGED
data/sd_struct.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sd_struct
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adrian Setyadi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-09-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '3.5'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.10.4
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.10.4
|
69
83
|
description: |-
|
70
84
|
An alternative to OpenStruct that more strict in assigning values and deeper in
|
71
85
|
consuming the passed Hash and transforming it back to Hash or JSON, equipped
|