ryo.rb 0.4.4
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 +7 -0
- data/.github/workflows/specs.yml +23 -0
- data/.gitignore +6 -0
- data/.gitlab-ci.yml +9 -0
- data/.rubocop.yml +56 -0
- data/.yardoc-template/default/fulldoc/html/css/0x1eef.css +15 -0
- data/.yardoc-template/default/layout/html/setup.rb +5 -0
- data/.yardoc-template/default/module/setup.rb +7 -0
- data/.yardopts +4 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +373 -0
- data/Rakefile +3 -0
- data/lib/ryo/basic_object.rb +58 -0
- data/lib/ryo/builder.rb +106 -0
- data/lib/ryo/enumerable.rb +214 -0
- data/lib/ryo/function.rb +68 -0
- data/lib/ryo/keywords.rb +67 -0
- data/lib/ryo/lazy.rb +4 -0
- data/lib/ryo/object.rb +58 -0
- data/lib/ryo/reflect.rb +379 -0
- data/lib/ryo/version.rb +5 -0
- data/lib/ryo.rb +197 -0
- data/ryo.rb.gemspec +21 -0
- data/share/ryo.rb/examples/1.0_prototypes_point_object.rb +12 -0
- data/share/ryo.rb/examples/1.1_prototypes_ryo_fn.rb +14 -0
- data/share/ryo.rb/examples/2.0_iteration_each.rb +13 -0
- data/share/ryo.rb/examples/2.1_iteration_map.rb +16 -0
- data/share/ryo.rb/examples/2.2_iteration_ancestors.rb +13 -0
- data/share/ryo.rb/examples/3.0_recursion_ryo_from.rb +13 -0
- data/share/ryo.rb/examples/3.1_recursion_ryo_from_with_array.rb +19 -0
- data/share/ryo.rb/examples/3.2_recursion_ryo_from_with_openstruct.rb +14 -0
- data/share/ryo.rb/examples/4.0_basicobject_ryo_basicobject.rb +12 -0
- data/share/ryo.rb/examples/4.1_basicobject_ryo_basicobject_from.rb +13 -0
- data/share/ryo.rb/examples/5_collisions_resolution_strategy.rb +8 -0
- data/share/ryo.rb/examples/6_beyond_hash_objects.rb +20 -0
- data/share/ryo.rb/examples/7_ryo_lazy.rb +14 -0
- data/share/ryo.rb/examples/setup.rb +3 -0
- data/spec/readme_spec.rb +79 -0
- data/spec/ryo_basic_object_spec.rb +60 -0
- data/spec/ryo_enumerable_spec.rb +197 -0
- data/spec/ryo_keywords_spec.rb +86 -0
- data/spec/ryo_object_spec.rb +71 -0
- data/spec/ryo_prototypes_spec.rb +45 -0
- data/spec/ryo_reflect_spec.rb +175 -0
- data/spec/ryo_spec.rb +130 -0
- data/spec/setup.rb +5 -0
- metadata +173 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 61ffcab409332ea4c6979e302c9d27f467575ef2b8167f07805e7f20ad523002
|
4
|
+
data.tar.gz: fb5f3050e9a373616e377a5d76c0605f7ce6e655ca8a2822619dd63d7426182d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1158833ffda85f18fabdb7f7830fe0a104f91bfe5d19d2f0d8a21e51ac5d95d34dd6744d100b0ba6e0c5c6ece7ecdd38a80f59f2ceb55898403d490de9be14b6
|
7
|
+
data.tar.gz: c92c24f793503360539dc314c1c15d9349f23efee1cc29ca9af2dab497528d1b7186f77ee839f7ce36592c223ae6a4b8bdd058cb00091361a098268bad0e5af3
|
@@ -0,0 +1,23 @@
|
|
1
|
+
name: Ryo specs
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ main ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ main ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
specs:
|
11
|
+
strategy:
|
12
|
+
fail-fast: false
|
13
|
+
matrix:
|
14
|
+
os: [ubuntu-latest]
|
15
|
+
ruby: [3.1, 3.2]
|
16
|
+
runs-on: ${{ matrix.os }}
|
17
|
+
steps:
|
18
|
+
- uses: actions/checkout@v2
|
19
|
+
- uses: ruby/setup-ruby@v1
|
20
|
+
with:
|
21
|
+
ruby-version: ${{ matrix.ruby }}
|
22
|
+
- run: bundle install
|
23
|
+
- run: rspec -Ilib -rryo spec/
|
data/.gitignore
ADDED
data/.gitlab-ci.yml
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
##
|
2
|
+
# Plugins
|
3
|
+
require:
|
4
|
+
- standard
|
5
|
+
- rubocop-rspec
|
6
|
+
|
7
|
+
##
|
8
|
+
# Defaults: standard-rb
|
9
|
+
inherit_gem:
|
10
|
+
standard: config/base.yml
|
11
|
+
|
12
|
+
##
|
13
|
+
# Enabled cops
|
14
|
+
Style/FrozenStringLiteralComment:
|
15
|
+
Enabled: true
|
16
|
+
|
17
|
+
##
|
18
|
+
# Disabled cops
|
19
|
+
Layout/MultilineMethodCallIndentation:
|
20
|
+
Enabled: false
|
21
|
+
Style/LambdaCall:
|
22
|
+
Enabled: false
|
23
|
+
Lint/AssignmentInCondition:
|
24
|
+
Enabled: false
|
25
|
+
|
26
|
+
##
|
27
|
+
# Disabled cops (rspec)
|
28
|
+
RSpec/FilePath:
|
29
|
+
Enabled: false
|
30
|
+
RSpec/NestedGroups:
|
31
|
+
Enabled: false
|
32
|
+
RSpec/NotToNot:
|
33
|
+
Enabled: false
|
34
|
+
RSpec/EmptyLineAfterHook:
|
35
|
+
Enabled: false
|
36
|
+
RSpec/EmptyLineAfterSubject:
|
37
|
+
Enabled: false
|
38
|
+
RSpec/DescribedClass:
|
39
|
+
Enabled: false
|
40
|
+
RSpec/MultipleExpectations:
|
41
|
+
Enabled: false
|
42
|
+
RSpec/EmptyLineAfterFinalLet:
|
43
|
+
Enabled: false
|
44
|
+
Style/NilComparison:
|
45
|
+
Exclude:
|
46
|
+
- spec/ryo_object_spec.rb
|
47
|
+
RSpec/DescribeClass:
|
48
|
+
Enabled: false
|
49
|
+
|
50
|
+
AllCops:
|
51
|
+
Include:
|
52
|
+
- 'lib/*.rb'
|
53
|
+
- 'lib/**/*.rb'
|
54
|
+
- 'spec/*.rb'
|
55
|
+
- 'spec/**/*.rb'
|
56
|
+
TargetRubyVersion: 3.2
|
data/.yardopts
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright 2022
|
4
|
+
0x1eef
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
14
|
+
copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,373 @@
|
|
1
|
+
## About
|
2
|
+
|
3
|
+
Ryo implements prototype-based inheritance, in Ruby.
|
4
|
+
|
5
|
+
Ryo's implementation of prototype-based inheritance offers
|
6
|
+
a flexible approach for establishing object relationships,
|
7
|
+
and building configuration objects. Ryo can also act as a
|
8
|
+
recursive OpenStruct alternative. JavaScript's implementation of
|
9
|
+
prototype-based inheritance served as a reference point
|
10
|
+
for Ryo's implementation.
|
11
|
+
|
12
|
+
## Examples
|
13
|
+
|
14
|
+
### Prototypes
|
15
|
+
|
16
|
+
#### Point object
|
17
|
+
|
18
|
+
The following example demonstrates how prototype-based inheritance is
|
19
|
+
implemented in Ryo. The example introduces three objects to form a
|
20
|
+
single point object with the properties, "x" and "y". The
|
21
|
+
[Ryo()](https://0x1eef.github.io/x/ryo.rb/top-level-namespace.html#Ryo-instance_method)
|
22
|
+
method seen in the example returns an instance of
|
23
|
+
[Ryo::Object](https://0x1eef.github.io/x/ryo.rb/Ryo/Object.html):
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
require "ryo"
|
27
|
+
|
28
|
+
point_x = Ryo(x: 5)
|
29
|
+
point_y = Ryo({y: 10}, point_x)
|
30
|
+
point = Ryo({}, point_y)
|
31
|
+
p [point.x, point.y]
|
32
|
+
|
33
|
+
##
|
34
|
+
# [5, 10]
|
35
|
+
```
|
36
|
+
|
37
|
+
#### Ryo.fn
|
38
|
+
|
39
|
+
The following example demonstrates a Ryo function.
|
40
|
+
[`Ryo.fn`](https://0x1eef.github.io/x/ryo.rb/Ryo/Keywords.html#function-instance_method)
|
41
|
+
will bind its `self` to the Ryo object it is assigned to, and when the function
|
42
|
+
is called it will have access to the properties of the Ryo object:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
require "ryo"
|
46
|
+
|
47
|
+
point_x = Ryo(x: 5)
|
48
|
+
point_y = Ryo({y: 10}, point_x)
|
49
|
+
point = Ryo({
|
50
|
+
multiply: Ryo.fn { |m| [x * m, y * m] }
|
51
|
+
}, point_y)
|
52
|
+
p point.multiply.call(2)
|
53
|
+
|
54
|
+
##
|
55
|
+
# [10, 20]
|
56
|
+
```
|
57
|
+
|
58
|
+
#### Ryo.lazy
|
59
|
+
|
60
|
+
The following example demonstrates a lazy Ryo value.
|
61
|
+
[`Ryo.lazy`](https://0x1eef.github.io/x/ryo.rb/Ryo.html#lazy-class_method)
|
62
|
+
creates a lazy value that is not evaluated until a property is accessed
|
63
|
+
for the first time. It is similar to a Ryo function but it does not require
|
64
|
+
that the `#call` method be used, and after the property is accessed for the
|
65
|
+
first time the lazy value is replaced by the evaluated value:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
require "ryo"
|
69
|
+
|
70
|
+
point_x = Ryo(x: Ryo.lazy { 5 })
|
71
|
+
point_y = Ryo({y: Ryo.lazy { 10 }}, point_x)
|
72
|
+
point = Ryo({sum: Ryo.lazy { x + y }}, point_y)
|
73
|
+
print "point.x = ", point.x, "\n"
|
74
|
+
print "point.y = ", point.y, "\n"
|
75
|
+
print "point.sum = ", point.sum, "\n"
|
76
|
+
|
77
|
+
##
|
78
|
+
# point.x = 5
|
79
|
+
# point.y = 10
|
80
|
+
# point.sum = 15
|
81
|
+
```
|
82
|
+
|
83
|
+
|
84
|
+
### Iteration
|
85
|
+
|
86
|
+
#### Ryo.each
|
87
|
+
|
88
|
+
The
|
89
|
+
[`Ryo.each`](https://0x1eef.github.io/x/ryo.rb/Ryo.html#each-class_method)
|
90
|
+
method can iterate through the properties of a Ryo object, and
|
91
|
+
its prototype(s). Ryo is designed to not mix its implementation
|
92
|
+
with the objects it creates - that's why
|
93
|
+
[`Ryo.each`](https://0x1eef.github.io/x/ryo.rb/Ryo.html#each-class_method)
|
94
|
+
is not implemented directly on a Ryo object.
|
95
|
+
|
96
|
+
A demonstration of [`Ryo.each`](https://0x1eef.github.io/x/ryo.rb/Ryo.html#each-class_method):
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
require "ryo"
|
100
|
+
|
101
|
+
point = Ryo(x: 10, y: 20)
|
102
|
+
Ryo.each(point) do |key, value|
|
103
|
+
p [key, value]
|
104
|
+
end
|
105
|
+
|
106
|
+
##
|
107
|
+
# ["x", 10]
|
108
|
+
# ["y", 20]
|
109
|
+
```
|
110
|
+
|
111
|
+
#### Ryo.map!
|
112
|
+
|
113
|
+
[`Ryo::Enumerable`](http://0x1eef.github.io/x/ryo.rb/Ryo/Enumerable.html)
|
114
|
+
methods can return a new copy of a Ryo object and its prototypes, or mutate
|
115
|
+
a Ryo object and its prototypes in-place. The following example demonstrates
|
116
|
+
an in-place map operation on a Ryo object with
|
117
|
+
[`Ryo.map!`](http://0x1eef.github.io/x/ryo.rb/Ryo/Enumerable.html#map!-instance_method).
|
118
|
+
The counterpart of
|
119
|
+
[`Ryo.map!`](http://0x1eef.github.io/x/ryo.rb/Ryo/Enumerable.html#map!-instance_method)
|
120
|
+
is
|
121
|
+
[`Ryo.map`](http://0x1eef.github.io/x/ryo.rb/Ryo/Enumerable.html#map-instance_method),
|
122
|
+
and it returns a new copy of a Ryo object and its prototypes.
|
123
|
+
|
124
|
+
A demonstration of [`Ryo.map!`](http://0x1eef.github.io/x/ryo.rb/Ryo/Enumerable.html#map!-instance_method):
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
require "ryo"
|
128
|
+
|
129
|
+
point_x = Ryo(x: 2)
|
130
|
+
point_y = Ryo({y: 4}, point_x)
|
131
|
+
point = Ryo({}, point_y)
|
132
|
+
|
133
|
+
Ryo.map!(point) { |key, value| value * 2 }
|
134
|
+
p [point.x, point.y]
|
135
|
+
p [point_x.x, point_y.y]
|
136
|
+
|
137
|
+
##
|
138
|
+
# [4, 8]
|
139
|
+
# [4, 8]
|
140
|
+
```
|
141
|
+
|
142
|
+
#### Ancestors
|
143
|
+
|
144
|
+
All [`Ryo::Enumerable`](http://0x1eef.github.io/x/ryo.rb/Ryo/Enumerable.html)
|
145
|
+
methods support an optional `ancestors` option.
|
146
|
+
|
147
|
+
`ancestors` is an integer that determines how far up the prototype chain a
|
148
|
+
[`Ryo::Enumerable`](https://0x1eef.github.io/x/ryo.rb/Ryo/Enumerable.html)
|
149
|
+
method can go. 0 covers a Ryo object, and none of the prototypes in its
|
150
|
+
prototype chain. 1 covers a Ryo object, and one of the prototypes in its
|
151
|
+
prototype chain - and so on.
|
152
|
+
|
153
|
+
When the `ancestors` option is not provided, the default behavior of
|
154
|
+
[`Ryo::Enumerable`](http://0x1eef.github.io/x/ryo.rb/Ryo/Enumerable.html)
|
155
|
+
methods is to traverse the entire prototype chain. The following example
|
156
|
+
demonstrates using the `ancestors` option with
|
157
|
+
[`Ryo.find`](https://0x1eef.github.io/x/ryo.rb/Ryo.html#find-class_method):
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
require "ryo"
|
161
|
+
|
162
|
+
point_x = Ryo(x: 5)
|
163
|
+
point_y = Ryo({y: 10}, point_x)
|
164
|
+
point = Ryo({}, point_y)
|
165
|
+
|
166
|
+
p Ryo.find(point, ancestors: 0) { |k,v| v == 5 } # => nil
|
167
|
+
p Ryo.find(point, ancestors: 1) { |k,v| v == 5 } # => nil
|
168
|
+
p Ryo.find(point, ancestors: 2) { |k,v| v == 5 }.x # => point_x.x
|
169
|
+
p Ryo.find(point) { |k,v| v == 5 }.x # => point_x.x
|
170
|
+
```
|
171
|
+
|
172
|
+
### Recursion
|
173
|
+
|
174
|
+
#### Ryo.from
|
175
|
+
|
176
|
+
The [`Ryo.from`](https://0x1eef.github.io/x/ryo.rb/Ryo.html#from-class_method) method has
|
177
|
+
the same interface as the [`Ryo`](https://0x1eef.github.io/x/ryo.rb/top-level-namespace.html#Ryo-instance_method)
|
178
|
+
method, but it is implemented to recursively walk a Hash object and create Ryo objects
|
179
|
+
from other Hash objects found along the way. Recursion is not the default behavior
|
180
|
+
because it has the potential to be slow when given a complex Hash object that's
|
181
|
+
very large - otherwise there shouldn't be a noticeable performance impact.
|
182
|
+
|
183
|
+
The following example demonstrates [`Ryo.from`](https://0x1eef.github.io/x/ryo.rb/Ryo.html#from-class_method):
|
184
|
+
|
185
|
+
```ruby
|
186
|
+
require "ryo"
|
187
|
+
|
188
|
+
point = Ryo.from({
|
189
|
+
x: {to_i: 0},
|
190
|
+
y: {to_i: 10}
|
191
|
+
})
|
192
|
+
p [point.x.to_i, point.y.to_i]
|
193
|
+
|
194
|
+
##
|
195
|
+
# [0, 10]
|
196
|
+
```
|
197
|
+
|
198
|
+
#### Ryo.from with an Array
|
199
|
+
|
200
|
+
The [`Ryo.from`](https://0x1eef.github.io/x/ryo.rb/Ryo.html#from-class_method) method can
|
201
|
+
walk an Array object, and create Ryo objects from Hash objects found along the way.
|
202
|
+
An object that can't be turned into a Ryo object is left as-is. The following
|
203
|
+
example demonstrates how that works in practice:
|
204
|
+
|
205
|
+
``` ruby
|
206
|
+
require "ryo"
|
207
|
+
|
208
|
+
points = Ryo.from([
|
209
|
+
{x: {to_i: 2}},
|
210
|
+
"foobar",
|
211
|
+
{y: {to_i: 4}}
|
212
|
+
])
|
213
|
+
|
214
|
+
p points[0].x.to_i
|
215
|
+
p points[1]
|
216
|
+
p points[2].y.to_i
|
217
|
+
|
218
|
+
##
|
219
|
+
# 2
|
220
|
+
# "foobar"
|
221
|
+
# 4
|
222
|
+
```
|
223
|
+
|
224
|
+
#### Ryo.from with OpenStruct
|
225
|
+
|
226
|
+
All methods that can create Ryo objects support turning a Struct, or OpenStruct object
|
227
|
+
into a Ryo object. The following example demonstrates how
|
228
|
+
[`Ryo.from`](https://0x1eef.github.io/x/ryo.rb/Ryo.html#from-class_method)
|
229
|
+
can recursively turn an OpenStruct object into Ryo objects. The example also assigns
|
230
|
+
a prototype to the Ryo object created from the OpenStruct:
|
231
|
+
|
232
|
+
``` ruby
|
233
|
+
require "ryo"
|
234
|
+
require "ostruct"
|
235
|
+
|
236
|
+
point = Ryo.from(
|
237
|
+
OpenStruct.new(x: {to_i: 5}),
|
238
|
+
Ryo.from(y: {to_i: 10})
|
239
|
+
)
|
240
|
+
p [point.x.to_i, point.y.to_i]
|
241
|
+
|
242
|
+
##
|
243
|
+
# [5, 10]
|
244
|
+
```
|
245
|
+
|
246
|
+
### BasicObject
|
247
|
+
|
248
|
+
#### Ryo::BasicObject
|
249
|
+
|
250
|
+
All of the previous examples have been working with instances of
|
251
|
+
[Ryo::Object](https://0x1eef.github.io/x/ryo.rb/Ryo/Object.html),
|
252
|
+
a subclass of Ruby's Object class. In comparison, [Ryo::BasicObject](https://0x1eef.github.io/x/ryo.rb/Ryo/BasicObject.html) -
|
253
|
+
a subclass of Ruby's BasicObject class, provides an object
|
254
|
+
with fewer methods. The following example demonstrates
|
255
|
+
how to create an instance of [Ryo::BasicObject](https://0x1eef.github.io/x/ryo.rb/Ryo/BasicObject.html):
|
256
|
+
|
257
|
+
```ruby
|
258
|
+
require "ryo"
|
259
|
+
|
260
|
+
point_x = Ryo::BasicObject(x: 0)
|
261
|
+
point_y = Ryo::BasicObject({y: 0}, point_x)
|
262
|
+
point = Ryo::BasicObject({}, point_y)
|
263
|
+
p [point.x, point.y]
|
264
|
+
|
265
|
+
##
|
266
|
+
# [0, 0]
|
267
|
+
```
|
268
|
+
|
269
|
+
#### Ryo::BasicObject.from
|
270
|
+
|
271
|
+
[Ryo::BasicObject.from](https://0x1eef.github.io/x/ryo.rb/Ryo/BasicObject.html#from-class_method)
|
272
|
+
is identical to Ryo.from but rather than returning instance(s) of [Ryo::Object](https://0x1eef.github.io/x/ryo.rb/Ryo/Object.html)
|
273
|
+
it returns instance(s) of [Ryo::BasicObject](https://0x1eef.github.io/x/ryo.rb/Ryo/BasicObject.html)
|
274
|
+
instead:
|
275
|
+
|
276
|
+
```ruby
|
277
|
+
require "ryo"
|
278
|
+
|
279
|
+
point = Ryo::BasicObject.from({
|
280
|
+
x: {to_i: 2},
|
281
|
+
y: {to_i: 4}
|
282
|
+
})
|
283
|
+
p [point.x.to_i, point.y.to_i]
|
284
|
+
|
285
|
+
##
|
286
|
+
# [2, 4]
|
287
|
+
```
|
288
|
+
|
289
|
+
### Collisions
|
290
|
+
|
291
|
+
#### Resolution strategy
|
292
|
+
|
293
|
+
When a property and method collide, Ryo tries to find the best resolution. Since Ryo properties
|
294
|
+
don't accept arguments, and methods can - we are able to distinguish a property from a method in
|
295
|
+
many cases.
|
296
|
+
|
297
|
+
Consider this example, where a property collides with the `Kernel#then` method. This example
|
298
|
+
would work the same for other methods that accept a block and/or arguments:
|
299
|
+
|
300
|
+
```ruby
|
301
|
+
require "ryo"
|
302
|
+
|
303
|
+
ryo = Ryo::Object(then: 12)
|
304
|
+
p ryo.then # => 12
|
305
|
+
p ryo.then { 34 } # => 34
|
306
|
+
```
|
307
|
+
|
308
|
+
### Beyond Hash objects
|
309
|
+
|
310
|
+
#### Duck typing
|
311
|
+
|
312
|
+
The documentation has used simple terms to describe the objects that Ryo works
|
313
|
+
with: Hash and Array objects. But actually, Ryo uses duck typing, so any object
|
314
|
+
that implements `#each_pair` can be treated as a Hash object, and any object that
|
315
|
+
implements `#each` can be treated as an Array object. Note that only
|
316
|
+
[Ryo.from](https://0x1eef.github.io/x/ryo.rb/Ryo.html#from-class_method),
|
317
|
+
[Ryo::Object.from](https://0x1eef.github.io/x/ryo.rb/Ryo/Object.html#from-class_method)
|
318
|
+
and
|
319
|
+
[Ryo::BasicObject.from](https://0x1eef.github.io/x/ryo.rb/Ryo/BasicObject.html#from-class_method)
|
320
|
+
can handle Array/#each objects.
|
321
|
+
|
322
|
+
Here's an example of how to turn your own custom object, which implements
|
323
|
+
`#each_pair`, into a Ryo object:
|
324
|
+
|
325
|
+
``` ruby
|
326
|
+
require "ryo"
|
327
|
+
|
328
|
+
class Point
|
329
|
+
def initialize
|
330
|
+
@x = 5
|
331
|
+
@y = 10
|
332
|
+
end
|
333
|
+
|
334
|
+
def each_pair
|
335
|
+
yield("x", @x)
|
336
|
+
yield("y", @y)
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
point = Ryo(Point.new)
|
341
|
+
p point.x # => 5
|
342
|
+
p point.y # => 10
|
343
|
+
```
|
344
|
+
|
345
|
+
## Sources
|
346
|
+
|
347
|
+
* [Source code (GitHub)](https://github.com/0x1eef/ryo.rb#readme)
|
348
|
+
* [Source code (GitLab)](https://gitlab.com/0x1eef/ryo.rb#about)
|
349
|
+
|
350
|
+
## <a id='install'>Install</a>
|
351
|
+
|
352
|
+
Ryo is distributed as a RubyGem through its git repositories. <br>
|
353
|
+
[GitHub](https://github.com/0x1eef/ryo.rb),
|
354
|
+
and
|
355
|
+
[GitLab](https://gitlab.com/0x1eef/ryo.rb)
|
356
|
+
are available as sources.
|
357
|
+
|
358
|
+
**Gemfile**
|
359
|
+
|
360
|
+
```ruby
|
361
|
+
gem "ryo.rb", github: "0x1eef/ryo.rb", tag: "v0.4.4"
|
362
|
+
```
|
363
|
+
|
364
|
+
## Thanks
|
365
|
+
|
366
|
+
Thanks to
|
367
|
+
[@awfulcooking (mooff)](https://github.com/awfulcooking)
|
368
|
+
for the helpful discussions and advice.
|
369
|
+
|
370
|
+
## License
|
371
|
+
|
372
|
+
This project is released under the terms of the MIT license. <br>
|
373
|
+
See [./LICENSE.txt](./LICENSE.txt) for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# {Ryo::BasicObject Ryo::BasicObject} is a Ryo object and subclass
|
5
|
+
# of Ruby's BasicObject class that can be created by using
|
6
|
+
# {Ryo.BasicObject Ryo.BasicObject()},
|
7
|
+
# {Ryo::BasicObject.from Ryo::BasicObject.from}, or
|
8
|
+
# {Ryo::BasicObject.create Ryo::BasicObject.create}.
|
9
|
+
class Ryo::BasicObject < BasicObject
|
10
|
+
##
|
11
|
+
# @param props (see Ryo::Builder.build)
|
12
|
+
# @param prototype (see Ryo::Builder.build)
|
13
|
+
#
|
14
|
+
# @return [Ryo::BasicObject]
|
15
|
+
# Returns an instance of {Ryo::BasicObject Ryo::BasicObject}.
|
16
|
+
def self.create(props, prototype = nil)
|
17
|
+
::Ryo::Builder.build(self, props, prototype)
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Creates a Ryo object by recursively walking a Hash object.
|
22
|
+
#
|
23
|
+
# @param props (see Ryo::Builder.recursive_build)
|
24
|
+
# @param prototype (see Ryo::Builder.recursive_build)
|
25
|
+
#
|
26
|
+
# @return [Ryo::BasicObject]
|
27
|
+
# Returns an instance of {Ryo::BasicObject Ryo::BasicObject}.
|
28
|
+
def self.from(props, prototype = nil)
|
29
|
+
::Ryo::Builder.recursive_build(self, props, prototype)
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Duplicates the internals of a Ryo object.
|
34
|
+
#
|
35
|
+
# @param [Ryo::BasicObject] ryo
|
36
|
+
# A Ryo object.
|
37
|
+
#
|
38
|
+
# @return [Ryo::BasicObject]
|
39
|
+
# Returns a Ryo object.
|
40
|
+
def initialize_dup(ryo)
|
41
|
+
::Ryo.set_table_of(self, ::Ryo.table_of(ryo).dup)
|
42
|
+
::Ryo.extend!(self, ::Ryo)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# @example
|
48
|
+
# point = Ryo::BasicObject(x: 0, y: 0)
|
49
|
+
# p [point.x, point.y] # => [0, 0]
|
50
|
+
#
|
51
|
+
# @param props (see Ryo::Builder.build)
|
52
|
+
# @param prototype (see Ryo::Builder.build)
|
53
|
+
#
|
54
|
+
# @return [Ryo::BasicObject]
|
55
|
+
# Returns an instance of {Ryo::BasicObject Ryo::BasicObject}.
|
56
|
+
def Ryo.BasicObject(props, prototype = nil)
|
57
|
+
Ryo::BasicObject.create(props, prototype)
|
58
|
+
end
|