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.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/specs.yml +23 -0
  3. data/.gitignore +6 -0
  4. data/.gitlab-ci.yml +9 -0
  5. data/.rubocop.yml +56 -0
  6. data/.yardoc-template/default/fulldoc/html/css/0x1eef.css +15 -0
  7. data/.yardoc-template/default/layout/html/setup.rb +5 -0
  8. data/.yardoc-template/default/module/setup.rb +7 -0
  9. data/.yardopts +4 -0
  10. data/Gemfile +5 -0
  11. data/LICENSE.txt +22 -0
  12. data/README.md +373 -0
  13. data/Rakefile +3 -0
  14. data/lib/ryo/basic_object.rb +58 -0
  15. data/lib/ryo/builder.rb +106 -0
  16. data/lib/ryo/enumerable.rb +214 -0
  17. data/lib/ryo/function.rb +68 -0
  18. data/lib/ryo/keywords.rb +67 -0
  19. data/lib/ryo/lazy.rb +4 -0
  20. data/lib/ryo/object.rb +58 -0
  21. data/lib/ryo/reflect.rb +379 -0
  22. data/lib/ryo/version.rb +5 -0
  23. data/lib/ryo.rb +197 -0
  24. data/ryo.rb.gemspec +21 -0
  25. data/share/ryo.rb/examples/1.0_prototypes_point_object.rb +12 -0
  26. data/share/ryo.rb/examples/1.1_prototypes_ryo_fn.rb +14 -0
  27. data/share/ryo.rb/examples/2.0_iteration_each.rb +13 -0
  28. data/share/ryo.rb/examples/2.1_iteration_map.rb +16 -0
  29. data/share/ryo.rb/examples/2.2_iteration_ancestors.rb +13 -0
  30. data/share/ryo.rb/examples/3.0_recursion_ryo_from.rb +13 -0
  31. data/share/ryo.rb/examples/3.1_recursion_ryo_from_with_array.rb +19 -0
  32. data/share/ryo.rb/examples/3.2_recursion_ryo_from_with_openstruct.rb +14 -0
  33. data/share/ryo.rb/examples/4.0_basicobject_ryo_basicobject.rb +12 -0
  34. data/share/ryo.rb/examples/4.1_basicobject_ryo_basicobject_from.rb +13 -0
  35. data/share/ryo.rb/examples/5_collisions_resolution_strategy.rb +8 -0
  36. data/share/ryo.rb/examples/6_beyond_hash_objects.rb +20 -0
  37. data/share/ryo.rb/examples/7_ryo_lazy.rb +14 -0
  38. data/share/ryo.rb/examples/setup.rb +3 -0
  39. data/spec/readme_spec.rb +79 -0
  40. data/spec/ryo_basic_object_spec.rb +60 -0
  41. data/spec/ryo_enumerable_spec.rb +197 -0
  42. data/spec/ryo_keywords_spec.rb +86 -0
  43. data/spec/ryo_object_spec.rb +71 -0
  44. data/spec/ryo_prototypes_spec.rb +45 -0
  45. data/spec/ryo_reflect_spec.rb +175 -0
  46. data/spec/ryo_spec.rb +130 -0
  47. data/spec/setup.rb +5 -0
  48. 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
@@ -0,0 +1,6 @@
1
+ doc/
2
+ .*rc
3
+ .*_history
4
+ .yardoc
5
+ *.lock
6
+ pkg/
data/.gitlab-ci.yml ADDED
@@ -0,0 +1,9 @@
1
+ stages:
2
+ - test
3
+
4
+ test-ruby32:
5
+ stage: test
6
+ image: ruby:3.2.1
7
+ script:
8
+ - bundle install
9
+ - bundle exec rspec spec/
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
@@ -0,0 +1,15 @@
1
+ #main #content #filecontents p, .discussion p, ul.param li, div.note {
2
+ max-width: 768px;
3
+ }
4
+
5
+ #toc {
6
+ position: fixed;
7
+ right: 25px;
8
+ display: none;
9
+ }
10
+
11
+ @media screen and (min-width: 1280px) {
12
+ #toc {
13
+ display: block;
14
+ }
15
+ }
@@ -0,0 +1,5 @@
1
+ def stylesheets
2
+ s = super
3
+ s << "css/0x1eef.css"
4
+ s
5
+ end
@@ -0,0 +1,7 @@
1
+ ##
2
+ # Sort methods in ascending order based
3
+ # on the line number where a method is
4
+ # defined.
5
+ def sort_listing(listing)
6
+ listing.sort_by { _1.files[1] }
7
+ end
data/.yardopts ADDED
@@ -0,0 +1,4 @@
1
+ -m markdown -M redcarpet --hide-void-return --no-private -t default -p .yardoc-template
2
+ -
3
+ README.md
4
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+ gem "test-cmd.rb", github: "0x1eef/test-cmd.rb", tag: "v0.4.0"
5
+ gemspec
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,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
@@ -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