ryo.rb 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,379 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # The {Ryo::Reflect Ryo::Reflect} module implements equivalents
5
+ # from JavaScript's [`Relfect` object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect),
6
+ # and equivalents for some of the static methods on JavaScript's
7
+ # [`Object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) constructor.
8
+ #
9
+ # This module also implements Ryo-specific reflection features as well. The
10
+ # instance methods of this module are available as singleton methods
11
+ # on the {Ryo Ryo} module.
12
+ module Ryo::Reflect
13
+ extend self
14
+
15
+ ##
16
+ # @group JavaScript equivalents (Reflect)
17
+
18
+ ##
19
+ # Equivalent to JavaScript's `Reflect.getPrototypeOf`.
20
+ #
21
+ # @param [Ryo] ryo
22
+ # A Ryo object.
23
+ #
24
+ # @return [Ryo, nil]
25
+ # Returns the prototype of the *ryo* object.
26
+ def prototype_of(ryo)
27
+ kernel(:instance_variable_get)
28
+ .bind_call(ryo, :@_proto)
29
+ end
30
+
31
+ ##
32
+ # Equivalent to JavaScript's `Reflect.setPrototypeOf`.
33
+ #
34
+ # @param [Ryo] ryo
35
+ # A Ryo object.
36
+ #
37
+ # @param [Ryo] prototype
38
+ # The prototype to assign to *ryo*.
39
+ #
40
+ # @return [nil]
41
+ def set_prototype_of(ryo, prototype)
42
+ kernel(:instance_variable_set)
43
+ .bind_call(ryo, :@_proto, prototype)
44
+ nil
45
+ end
46
+
47
+ ##
48
+ # Equivalent to JavaScript's `Reflect.defineProperty`.
49
+ #
50
+ # @param [<Ryo::Object, Ryo::BasicObject>] ryo
51
+ # A Ryo object.
52
+ #
53
+ # @param [<String, #to_s>] property
54
+ # The name of the property.
55
+ #
56
+ # @param [Object, BasicObject] value
57
+ # The value of the property.
58
+ #
59
+ # @return [void]
60
+ def define_property(ryo, property, value)
61
+ table, property = table_of(ryo), property.to_s
62
+ kernel(:tap).bind_call(value) { _1.bind!(ryo) if function?(_1) }
63
+ table[property] = value
64
+ # Define setter
65
+ if !setter_defined?(ryo, property) && property[-1] != "?"
66
+ define_method!(ryo, "#{property}=") { ryo[property] = _1 }
67
+ end
68
+ # Define getter
69
+ return if getter_defined?(ryo, property)
70
+ define_method!(ryo, property) { |*args, &b|
71
+ (args.empty? && b.nil?) ? ryo[property] :
72
+ super(*args, &b)
73
+ }
74
+ nil
75
+ end
76
+
77
+ ##
78
+ # Equivalent to JavaScript's `Reflect.ownKeys`, and
79
+ # JavaScript's `Object.keys`.
80
+ #
81
+ # @param [<Ryo::Object, Ryo::BasicObject>] ryo
82
+ # A Ryo object.
83
+ #
84
+ # @return [Array<String>]
85
+ # Returns the properties defined on a Ryo object.
86
+ def properties_of(ryo)
87
+ table_of(ryo).keys
88
+ end
89
+
90
+ # @endgroup
91
+
92
+ ##
93
+ # @group JavaScript equivalents (Object)
94
+
95
+ ##
96
+ # Equivalent to JavaScript's `Object.hasOwn`,
97
+ # and `Object.prototype.hasOwnProperty`.
98
+ #
99
+ # @param [<Ryo::Object, Ryo::BasicObject>] ryo
100
+ # A Ryo object.
101
+ #
102
+ # @param [<String, #to_s>] property
103
+ # A property name.
104
+ #
105
+ # @return [Boolean]
106
+ # Returns true when **property** is a member of a Ryo object.
107
+ def property?(ryo, property)
108
+ table_of(ryo).key?(property.to_s)
109
+ end
110
+
111
+ ##
112
+ # Equivalent to JavaScript's `Object.assign`.
113
+ #
114
+ #
115
+ # @param [Ryo, Hash, #to_hash] target
116
+ # The target object.
117
+ #
118
+ # @param [Ryo, Hash, #to_hash] sources
119
+ # A variable number of source objects that
120
+ # will be merged into the target object.
121
+ #
122
+ # @return [Ryo]
123
+ # Returns the modified target object.
124
+ def assign(target, *sources)
125
+ sources.each do |source|
126
+ to_hash(source).each { target[_1.to_s] = _2 }
127
+ end
128
+ target
129
+ end
130
+ # @endgroup
131
+
132
+ ##
133
+ # @group Ryo-specific
134
+
135
+ ##
136
+ # The {#delete!} method deletes a property from a Ryo object,
137
+ # and from the prototypes in its prototype chain.
138
+ #
139
+ # @see Ryo::Keywords#delete
140
+ #
141
+ # @param [<Ryo::Object, Ryo::BasicObject>] ryo
142
+ # A Ryo object.
143
+ #
144
+ # @param [<String, #to_s>] property
145
+ # A property name.
146
+ #
147
+ # @return [void]
148
+ def delete!(ryo, property)
149
+ [ryo, *prototype_chain_of(ryo)].each do
150
+ Ryo.delete(_1, property.to_s)
151
+ end
152
+ end
153
+
154
+ ##
155
+ # @param [<Ryo::Object, Ryo::BasicObject>] ryo
156
+ # A Ryo object.
157
+ #
158
+ # @return [Array<Ryo::Object, Ryo::BasicObject>]
159
+ # Returns the prototype chain of a Ryo object.
160
+ def prototype_chain_of(ryo)
161
+ prototypes = []
162
+ loop do
163
+ ryo = prototype_of(ryo)
164
+ break unless ryo
165
+ prototypes.push(ryo)
166
+ end
167
+ prototypes
168
+ end
169
+
170
+ ##
171
+ # @param [<Ryo::Object, Ryo::BasicObject>] ryo
172
+ # A Ryo object.
173
+ #
174
+ # @param [Boolean] recursive
175
+ # When true, nested Ryo objects are replaced by
176
+ # their table as well.
177
+ #
178
+ # @return [Hash]
179
+ # Returns the table of a Ryo object.
180
+ def table_of(ryo, recursive: false)
181
+ table = kernel(:instance_variable_get).bind_call(ryo, :@_table)
182
+ if recursive
183
+ table.each do |key, value|
184
+ if ryo?(value)
185
+ table[key] = table_of(value, recursive:)
186
+ end
187
+ end
188
+ end
189
+ table
190
+ end
191
+
192
+ ##
193
+ # Sets the table of a Ryo object.
194
+ #
195
+ # @param [<Ryo::Object, Ryo::BasicObject>] ryo
196
+ # A Ryo object.
197
+ #
198
+ # @param [Hash] table
199
+ # The table to assign to a Ryo object.
200
+ #
201
+ # @return [nil]
202
+ def set_table_of(ryo, table)
203
+ kernel(:instance_variable_set)
204
+ .bind_call(ryo, :@_table, table)
205
+ nil
206
+ end
207
+
208
+ ##
209
+ # @param [<Ryo::Object, Ryo::BasicObject>] ryo
210
+ # A Ryo object.
211
+ #
212
+ # @param [<String, Symbol>] method
213
+ # The name of a method.
214
+ #
215
+ # @param [::Object, ::BasicObject] args
216
+ # Zero or more arguments to call **method** with.
217
+ #
218
+ # @param [Proc] b
219
+ # An optional block to pass to **method**.
220
+ #
221
+ # @return [::Object, ::BasicObject]
222
+ # Returns the return value of the method call.
223
+ def call_method(ryo, method, *args, &b)
224
+ kernel(:__send__)
225
+ .bind_call(ryo, method, *args, &b)
226
+ end
227
+
228
+ ##
229
+ # @param [<Ryo::Object, Ryo::BasicObject>] ryo
230
+ # A Ryo object.
231
+ #
232
+ # @return [Class]
233
+ # Returns the class of a Ryo object.
234
+ def class_of(ryo)
235
+ kernel(:class).bind_call(ryo)
236
+ end
237
+
238
+ ##
239
+ # @param [Ryo::Function, Object, BasicObject] obj
240
+ # An object.
241
+ #
242
+ # @return [Boolean]
243
+ # Returns true when the given object is a Ryo function.
244
+ def function?(obj)
245
+ Ryo::Function === obj
246
+ end
247
+
248
+ ##
249
+ # @param [Ryo::Function, Object, BasicObject] obj
250
+ # An object.
251
+ #
252
+ # @return [Boolean]
253
+ # Returns true when the given object is an instance
254
+ # of {Ryo::Lazy Ryo::Lazy}.
255
+ def lazy?(obj)
256
+ Ryo::Lazy === obj
257
+ end
258
+
259
+ ##
260
+ # @example
261
+ # Ryo.ryo?(Ryo::Object(x: 5, y: 12)) # => true
262
+ # Ryo.ryo?(Ryo::BasicObject(x: 10, y: 20)) # => true
263
+ # Ryo.ryo?(Object.new) # => false
264
+ #
265
+ # @param [Object, BasicObject] obj
266
+ # An object.
267
+ #
268
+ # @return [Boolean]
269
+ # Returns true when the given object is a Ryo object.
270
+ def ryo?(obj)
271
+ Ryo === obj
272
+ end
273
+
274
+ ##
275
+ # @param [<Ryo::Object, Ryo::BasicObject>] ryo1
276
+ # A Ryo object.
277
+ #
278
+ # @param [<Ryo::Object, Ryo::BasicObject>] ryo2
279
+ # A Ryo object.
280
+ #
281
+ # @return [Boolean]
282
+ # Returns true when two Ryo objects are the same object.
283
+ def equal?(ryo1, ryo2)
284
+ kernel(:equal?).bind_call(ryo1, ryo2)
285
+ end
286
+
287
+ ##
288
+ # @param [<Ryo::Object, Ryo::BasicObject>] ryo
289
+ # A Ryo object.
290
+ #
291
+ # @return [String]
292
+ # Returns a String representation of a Ryo object.
293
+ def inspect_object(ryo)
294
+ format(
295
+ "#<Ryo object=%{object} proto=%{proto} table=%{table}>",
296
+ object: Object.instance_method(:to_s).bind_call(ryo),
297
+ proto: prototype_of(ryo).inspect,
298
+ table: table_of(ryo).inspect
299
+ )
300
+ end
301
+ # @endgroup
302
+
303
+ ##
304
+ # @param [<Ryo::Object, Ryo::BasicObject>] ryo
305
+ # A Ryo object.
306
+ #
307
+ # @param [<String, Symbol>] method
308
+ # The name of the method.
309
+ #
310
+ # @param [Proc] b
311
+ # The method's body.
312
+ #
313
+ # @private
314
+ private def define_method!(ryo, method, &b)
315
+ kernel(:define_singleton_method)
316
+ .bind_call(ryo, method, &b)
317
+ end
318
+
319
+ ##
320
+ # @param [<Ryo::Object, Ryo::BasicObject>] ryo
321
+ # A Ryo object.
322
+ #
323
+ # @param [<String, #to_s>] property
324
+ # The name of the property.
325
+ #
326
+ # @return [Boolean]
327
+ # Returns true when the property has been
328
+ # defined with a getter method.
329
+ #
330
+ # @private
331
+ private def getter_defined?(ryo, property)
332
+ kernel(:method)
333
+ .bind_call(ryo, property)
334
+ .source_location
335
+ &.dig(0) == __FILE__
336
+ end
337
+
338
+ ##
339
+ #
340
+ # @param [<Ryo::Object, Ryo::BasicObject>] ryo
341
+ # A Ryo object.
342
+ #
343
+ # @param [<String, #to_s>] property
344
+ # The name of the property.
345
+ #
346
+ # @return [Boolean]
347
+ # Returns true when the property has been
348
+ # defined with a setter method.
349
+ #
350
+ # @private
351
+ private def setter_defined?(ryo, property)
352
+ getter_defined?(ryo, "#{property}=")
353
+ end
354
+
355
+ ##
356
+ # @private
357
+ private def merge!(obj1, obj2)
358
+ obj1, obj2 = to_hash(obj1), to_hash(obj2)
359
+ obj2.each { obj1[_1.to_s] = _2 }
360
+ obj1
361
+ end
362
+
363
+ ##
364
+ # @private
365
+ private def to_hash(obj)
366
+ if ryo?(obj)
367
+ table_of(obj)
368
+ else
369
+ Hash.try_convert(obj)
370
+ end
371
+ end
372
+
373
+ ##
374
+ # @private
375
+ def kernel(name)
376
+ Module.instance_method(name)
377
+ end
378
+ # @endgroup
379
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ryo
4
+ VERSION = "0.4.4"
5
+ end
data/lib/ryo.rb ADDED
@@ -0,0 +1,197 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # The {Ryo Ryo} module implements most of its behavior as singleton methods
5
+ # that are inherited from the {Ryo::Reflect Ryo::Reflect}, and
6
+ # {Ryo::Keywords Ryo:Keywords} modules.
7
+ #
8
+ # @example
9
+ # # Ryo.delete
10
+ # point = Ryo(x: 0, y: 0)
11
+ # Ryo.delete(point, "x")
12
+ # point.x # => nil
13
+ #
14
+ # # Ryo.assign
15
+ # point = Ryo.assign(Ryo({}), {x: 0}, {y: 0})
16
+ # point.x # => 0
17
+ module Ryo
18
+ require_relative "ryo/reflect"
19
+ require_relative "ryo/keywords"
20
+ require_relative "ryo/builder"
21
+ require_relative "ryo/basic_object"
22
+ require_relative "ryo/object"
23
+ require_relative "ryo/function"
24
+ require_relative "ryo/lazy"
25
+ require_relative "ryo/enumerable"
26
+
27
+ extend Ryo::Reflect
28
+ extend Ryo::Keywords
29
+ extend Ryo::Enumerable
30
+
31
+ ##
32
+ # @param [<Ryo::Object, Ryo::BasicObject>] ryo
33
+ # A Ryo object.
34
+ #
35
+ # @param [Module] mod
36
+ # A module to extend a Ryo object with.
37
+ #
38
+ # @return [<Ryo::Object, Ryo::BasicObject>]
39
+ # Returns a Ryo object extended by **mod**.
40
+ def self.extend!(ryo, mod)
41
+ kernel(:extend).bind_call(ryo, mod)
42
+ end
43
+
44
+ ##
45
+ # Duplicates a Ryo object, and its prototype(s).
46
+ #
47
+ # @param [<Ryo::Object, Ryo::BasicObject>] ryo
48
+ # A Ryo object.
49
+ #
50
+ # @return [<Ryo::Object, Ryo::BasicObject>]
51
+ # Returns a duplicated Ryo object.
52
+ def self.dup(ryo)
53
+ duplicate = extend!(
54
+ kernel(:dup).bind_call(ryo),
55
+ self
56
+ )
57
+ if proto = prototype_of(duplicate)
58
+ set_prototype_of(duplicate, dup(proto))
59
+ end
60
+ duplicate
61
+ end
62
+
63
+ ##
64
+ # Creates a lazy Ryo value.
65
+ #
66
+ # @param [Proc] b
67
+ # A proc that is evaluated when a property is first accessed.
68
+ #
69
+ # @return [Ryo::Lazy]
70
+ # Returns an instance of {Ryo::Lazy Ryo::Lazy}.
71
+ def self.lazy(&b)
72
+ Ryo::Lazy.new(&b)
73
+ end
74
+
75
+ ##
76
+ # Creates a Ryo object by recursively walking a Hash object.
77
+ #
78
+ # @param props (see Ryo::Builder.build)
79
+ # @param prototype (see Ryo::Builder.build)
80
+ #
81
+ # @return [Ryo::Object]
82
+ # Returns an instance of {Ryo::Object Ryo::Object}.
83
+ def self.from(props, prototype = nil)
84
+ Ryo::Object.from(props, prototype)
85
+ end
86
+
87
+ ##
88
+ # Returns the prototype of self, or "nil" if self has no prototype.
89
+ #
90
+ # @return [<Ryo::Object, Ryo::BasicObject>, nil]
91
+ def __proto__
92
+ @_proto
93
+ end
94
+
95
+ ##
96
+ # @param [String] property
97
+ # A property name.
98
+ #
99
+ # @return [<Object, BasicObject>, nil]
100
+ # Returns the value at **property**, or nil.
101
+ #
102
+ # @note
103
+ # This method will first try to read **property** from self, and if
104
+ # it is not found on self the chain of prototypes will be traversed
105
+ # through instead.
106
+ def [](property)
107
+ property = property.to_s
108
+ if Ryo.property?(self, property)
109
+ v = @_table[property]
110
+ Ryo.lazy?(v) ? self[property] = v.call : v
111
+ else
112
+ return unless @_proto
113
+ Ryo.call_method(@_proto, property)
114
+ end
115
+ end
116
+
117
+ ##
118
+ # Assigns a property to self.
119
+ #
120
+ # @param [String] property
121
+ # A property name.
122
+ #
123
+ # @param [<Object,BasicObject>] value
124
+ # The value.
125
+ #
126
+ # @return [void]
127
+ def []=(property, value)
128
+ Ryo.define_property(self, property.to_s, value)
129
+ end
130
+
131
+ ##
132
+ # @param [<Ryo::Object, Ryo::BasicObject>, Hash, #to_h] other
133
+ # An object to compare against.
134
+ #
135
+ # @return [Boolean]
136
+ # Returns true **other** is equal to self.
137
+ def ==(other)
138
+ if Ryo.ryo?(other)
139
+ @_table == Ryo.table_of(other)
140
+ else
141
+ other = Hash.try_convert(other)
142
+ return false unless other
143
+ @_table == other.map { [_1.to_s, _2] }.to_h
144
+ end
145
+ end
146
+ alias_method :eql?, :==
147
+
148
+ ##
149
+ # @return [String]
150
+ # Returns a String representation of a Ryo object.
151
+ def inspect
152
+ Ryo.inspect_object(self)
153
+ end
154
+
155
+ ##
156
+ # @private
157
+ def pretty_print(q)
158
+ q.text(inspect)
159
+ end
160
+
161
+ ##
162
+ # @private
163
+ def respond_to?(property, include_all = false)
164
+ respond_to_missing?(property, include_all)
165
+ end
166
+
167
+ ##
168
+ # @private
169
+ def respond_to_missing?(property, include_all = false)
170
+ true
171
+ end
172
+
173
+ ##
174
+ # @private
175
+ def method_missing(name, *args, &b)
176
+ property = name.to_s
177
+ if property[-1] == "="
178
+ property = property[0..-2]
179
+ self[property] = args.first
180
+ elsif Ryo.property?(self, property)
181
+ self[property]
182
+ elsif @_proto
183
+ Ryo.call_method(@_proto, name, *args, &b)
184
+ .tap { _1.bind!(self) if Ryo.function?(_1) }
185
+ end
186
+ end
187
+ end
188
+
189
+ ##
190
+ # @param props (see Ryo::Builder.build)
191
+ # @param prototype (see Ryo::Builder.build)
192
+ #
193
+ # @return [Ryo::Object]
194
+ # Returns a Ryo object.
195
+ def Ryo(props, prototype = nil)
196
+ Ryo::Object.create(props, prototype)
197
+ end
data/ryo.rb.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "./lib/ryo/version"
4
+ Gem::Specification.new do |gem|
5
+ gem.name = "ryo.rb"
6
+ gem.authors = ["0x1eef"]
7
+ gem.email = ["0x1eef@protonmail.com"]
8
+ gem.homepage = "https://github.com/0x1eef/ryo.rb#readme"
9
+ gem.version = Ryo::VERSION
10
+ gem.licenses = ["MIT"]
11
+ gem.files = `git ls-files`.split($/)
12
+ gem.require_paths = ["lib"]
13
+ gem.description = "Ryo implements prototype-based inheritance, in Ruby."
14
+ gem.summary = gem.description
15
+ gem.add_development_dependency "yard", "~> 0.9"
16
+ gem.add_development_dependency "redcarpet", "~> 3.5"
17
+ gem.add_development_dependency "rspec", "~> 3.10"
18
+ gem.add_development_dependency "rubocop-rspec", "~> 2.12"
19
+ gem.add_development_dependency "standard", "~> 1.9"
20
+ gem.add_development_dependency "test-cmd.rb", "~> 0.4"
21
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "setup"
4
+ require "ryo"
5
+
6
+ point_x = Ryo(x: 5)
7
+ point_y = Ryo({y: 10}, point_x)
8
+ point = Ryo({}, point_y)
9
+ p [point.x, point.y]
10
+
11
+ ##
12
+ # [5, 10]
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "setup"
4
+ require "ryo"
5
+
6
+ point_x = Ryo(x: 5)
7
+ point_y = Ryo({y: 10}, point_x)
8
+ point = Ryo({
9
+ multiply: Ryo.fn { |m| [x * m, y * m] }
10
+ }, point_y)
11
+ p point.multiply.call(2)
12
+
13
+ ##
14
+ # [10, 20]
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "setup"
4
+ require "ryo"
5
+
6
+ point = Ryo(x: 10, y: 20)
7
+ Ryo.each(point) do |key, value|
8
+ p [key, value]
9
+ end
10
+
11
+ ##
12
+ # ["x", 10]
13
+ # ["y", 20]
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "setup"
4
+ require "ryo"
5
+
6
+ point_x = Ryo(x: 2)
7
+ point_y = Ryo({y: 4}, point_x)
8
+ point = Ryo({}, point_y)
9
+
10
+ Ryo.map!(point) { |key, value| value * 2 }
11
+ p [point.x, point.y]
12
+ p [point_x.x, point_y.y]
13
+
14
+ ##
15
+ # [4, 8]
16
+ # [4, 8]
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "setup"
4
+ require "ryo"
5
+
6
+ point_x = Ryo(x: 5)
7
+ point_y = Ryo({y: 10}, point_x)
8
+ point = Ryo({}, point_y)
9
+
10
+ p Ryo.find(point, ancestors: 0) { |k,v| v == 5 } # => nil
11
+ p Ryo.find(point, ancestors: 1) { |k,v| v == 5 } # => nil
12
+ p Ryo.find(point, ancestors: 2) { |k,v| v == 5 }.x # => point_x.x
13
+ p Ryo.find(point) { |k,v| v == 5 }.x # => point_x.x
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "setup"
4
+ require "ryo"
5
+
6
+ point = Ryo.from({
7
+ x: {to_i: 0},
8
+ y: {to_i: 10}
9
+ })
10
+ p [point.x.to_i, point.y.to_i]
11
+
12
+ ##
13
+ # [0, 10]
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "setup"
4
+ require "ryo"
5
+
6
+ points = Ryo.from([
7
+ {x: {to_i: 2}},
8
+ "foobar",
9
+ {y: {to_i: 4}}
10
+ ])
11
+
12
+ p points[0].x.to_i
13
+ p points[1]
14
+ p points[2].y.to_i
15
+
16
+ ##
17
+ # 2
18
+ # "foobar"
19
+ # 4