quran-audio 0.4.0 → 0.4.2
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/bundle/io-line.rb/lib/io/line/multiple.rb +19 -0
- data/bundle/io-line.rb/lib/io/line.rb +28 -0
- data/bundle/ryo.rb/lib/ryo/basic_object.rb +54 -0
- data/bundle/ryo.rb/lib/ryo/builder.rb +87 -0
- data/bundle/ryo.rb/lib/ryo/enumerable.rb +197 -0
- data/bundle/ryo.rb/lib/ryo/function.rb +68 -0
- data/bundle/ryo.rb/lib/ryo/json.rb +45 -0
- data/bundle/ryo.rb/lib/ryo/keywords.rb +55 -0
- data/bundle/ryo.rb/lib/ryo/memo.rb +4 -0
- data/bundle/ryo.rb/lib/ryo/object.rb +54 -0
- data/bundle/ryo.rb/lib/ryo/reflect.rb +264 -0
- data/bundle/ryo.rb/lib/ryo/utils.rb +68 -0
- data/bundle/ryo.rb/lib/ryo/version.rb +5 -0
- data/bundle/ryo.rb/lib/ryo/yaml.rb +45 -0
- data/bundle/ryo.rb/lib/ryo.rb +195 -0
- data/share/quran-audio/VERSION +1 -1
- metadata +16 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f31510aaf2b2ac45001870411b82eb1e1ff7c8103cdbebb4f9b92268906b4cfb
|
|
4
|
+
data.tar.gz: 6c54cbdf7ed5493fcb9cc0cf0e84305adae279c2433d5f1e6204ac9ba9af9b38
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c2a714b375cab47aea59c2f03132e291b4f8b617a271e75aeb15b7ee9c07b0835734a35ca3ef99d988604531d4c91a68fdad0aecbebaa184c857a0c0ff123d3a
|
|
7
|
+
data.tar.gz: a25e352aa4d91b529e9943e07d4a58ed49f4a9c6f40ad56249f60c9a3bc038b929fef304dba2f9da0357bc8a01b7aab7abc32f18498f9150e0fa5c101311e6c8
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class IO::Line::Multiple
|
|
4
|
+
def initialize(lines, cursor)
|
|
5
|
+
@lines = lines
|
|
6
|
+
@cursor = cursor
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def print(*strs, lineno:)
|
|
10
|
+
line = @lines[lineno]
|
|
11
|
+
if lineno > @cursor
|
|
12
|
+
line.io.cursor_down(lineno - @cursor)
|
|
13
|
+
elsif lineno < @cursor
|
|
14
|
+
line.io.cursor_up(lineno + @cursor)
|
|
15
|
+
end
|
|
16
|
+
@cursor = lineno
|
|
17
|
+
line.rewind.print(*strs)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class IO::Line
|
|
4
|
+
require "io/console"
|
|
5
|
+
require_relative "line/multiple"
|
|
6
|
+
|
|
7
|
+
VERSION = "0.1.0"
|
|
8
|
+
attr_reader :io
|
|
9
|
+
|
|
10
|
+
def initialize(io)
|
|
11
|
+
@io = io
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def print(*strs)
|
|
15
|
+
tap { @io.print(strs.join.gsub($/, "")) }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def end
|
|
19
|
+
tap { @io.print($/) }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def rewind
|
|
23
|
+
tap do
|
|
24
|
+
@io.erase_line(2)
|
|
25
|
+
@io.goto_column(0)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
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
|
+
# @return [Ryo::BasicObject]
|
|
14
|
+
# Returns an instance of {Ryo::BasicObject Ryo::BasicObject}
|
|
15
|
+
def self.create(props, prototype = nil)
|
|
16
|
+
::Ryo::Builder.build(self, props, prototype)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
##
|
|
20
|
+
# Creates a Ryo object by recursively walking a Hash object
|
|
21
|
+
#
|
|
22
|
+
# @param props (see Ryo::Builder.recursive_build)
|
|
23
|
+
# @param prototype (see Ryo::Builder.recursive_build)
|
|
24
|
+
# @return [Ryo::BasicObject]
|
|
25
|
+
# Returns an instance of {Ryo::BasicObject Ryo::BasicObject}
|
|
26
|
+
def self.from(props, prototype = nil)
|
|
27
|
+
::Ryo::Builder.recursive_build(self, props, prototype)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
##
|
|
31
|
+
# Duplicates the internals of a Ryo object
|
|
32
|
+
#
|
|
33
|
+
# @param [Ryo::BasicObject] ryo
|
|
34
|
+
# A Ryo object
|
|
35
|
+
# @return [Ryo::BasicObject]
|
|
36
|
+
# Returns a Ryo object
|
|
37
|
+
def initialize_dup(ryo)
|
|
38
|
+
::Ryo.set_table_of(self, ::Ryo.table_of(ryo).dup)
|
|
39
|
+
::Ryo.extend!(self, ::Ryo)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
##
|
|
44
|
+
# @example
|
|
45
|
+
# point = Ryo::BasicObject(x: 0, y: 0)
|
|
46
|
+
# p [point.x, point.y] # => [0, 0]
|
|
47
|
+
#
|
|
48
|
+
# @param props (see Ryo::Builder.build)
|
|
49
|
+
# @param prototype (see Ryo::Builder.build)
|
|
50
|
+
# @return [Ryo::BasicObject]
|
|
51
|
+
# Returns an instance of {Ryo::BasicObject Ryo::BasicObject}
|
|
52
|
+
def Ryo.BasicObject(props, prototype = nil)
|
|
53
|
+
Ryo::BasicObject.create(props, prototype)
|
|
54
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# The {Ryo::Builder Ryo::Builder} module is responsible for
|
|
5
|
+
# the creation of instances of {Ryo::Object Ryo::Object},
|
|
6
|
+
# and {Ryo::BasicObject Ryo::BasicObject}. This module is
|
|
7
|
+
# not intended to be used directly.
|
|
8
|
+
# @api private
|
|
9
|
+
module Ryo::Builder
|
|
10
|
+
##
|
|
11
|
+
# @note
|
|
12
|
+
# When "props" is given as a Ryo object, a duplicate Ryo object is
|
|
13
|
+
# returned in its place
|
|
14
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] buildee
|
|
15
|
+
# @param [<#each_pair>] props
|
|
16
|
+
# @param [<Ryo::Object, Ryo::BasicObject>, nil] prototype
|
|
17
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
|
18
|
+
# Returns a Ryo object
|
|
19
|
+
def self.build(buildee, props, prototype = nil)
|
|
20
|
+
if Ryo.ryo?(props)
|
|
21
|
+
build(buildee, Ryo.table_of(props), prototype || Ryo.prototype_of(props))
|
|
22
|
+
else
|
|
23
|
+
ryo = buildee.new
|
|
24
|
+
Ryo.set_prototype_of(ryo, prototype)
|
|
25
|
+
Ryo.set_table_of(ryo, {})
|
|
26
|
+
Ryo.extend!(ryo, Ryo)
|
|
27
|
+
props.each_pair { ryo[_1] = _2 }
|
|
28
|
+
ryo
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
##
|
|
33
|
+
# Creates a Ryo object by recursively walking a Hash object, or
|
|
34
|
+
# an Array of Hash objects
|
|
35
|
+
#
|
|
36
|
+
# @example
|
|
37
|
+
# objects = Ryo.from([{x: 0, y: 0}, "foo", {point: {x: 0, y: 0}}])
|
|
38
|
+
# objects[0].x # => 0
|
|
39
|
+
# objects[1] # => "foo"
|
|
40
|
+
# objects[2].point.x # => 0
|
|
41
|
+
#
|
|
42
|
+
# @note (see Ryo::Builder.build)
|
|
43
|
+
# @param (see Ryo::Builder.build)
|
|
44
|
+
# @return (see Ryo::Builder.build)
|
|
45
|
+
def self.recursive_build(buildee, props, prototype = nil)
|
|
46
|
+
if Ryo.ryo?(props)
|
|
47
|
+
recursive_build(buildee, Ryo.table_of(props), prototype || Ryo.prototype_of(props))
|
|
48
|
+
elsif !respond_to_each?(props)
|
|
49
|
+
raise TypeError, "The provided object does not implement #each / #each_pair"
|
|
50
|
+
elsif !props.respond_to?(:each_pair)
|
|
51
|
+
map(props) do
|
|
52
|
+
noop = Ryo.ryo?(_1) || !_1.respond_to?(:each_pair)
|
|
53
|
+
noop ? _1 : recursive_build(buildee, _1)
|
|
54
|
+
end
|
|
55
|
+
else
|
|
56
|
+
visited = {}
|
|
57
|
+
props.each_pair { visited[_1] = map_value(buildee, _2) }
|
|
58
|
+
build(buildee, visited, prototype)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
module Private
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def map_value(buildee, value)
|
|
66
|
+
if Ryo.ryo?(value) || !respond_to_each?(value)
|
|
67
|
+
value
|
|
68
|
+
elsif value.respond_to?(:each_pair)
|
|
69
|
+
recursive_build(buildee, value)
|
|
70
|
+
elsif value.respond_to?(:each)
|
|
71
|
+
map(value) { map_value(buildee, _1) }
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def respond_to_each?(value)
|
|
76
|
+
value.respond_to?(:each) || value.respond_to?(:each_pair)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def map(obj)
|
|
80
|
+
ary = []
|
|
81
|
+
obj.each { ary.push(yield(_1)) }
|
|
82
|
+
ary
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
private_constant :Private
|
|
86
|
+
extend Private
|
|
87
|
+
end
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# The {Ryo::Enumerable Ryo::Enumerable} module provides methods
|
|
5
|
+
# that are similar to Ruby's Enumerable module, and at the same
|
|
6
|
+
# time - intentionally different.
|
|
7
|
+
#
|
|
8
|
+
# For example: {Ryo::Enumerable Ryo::Enumerable}
|
|
9
|
+
# methods receive 'self' as an argument rather than from the
|
|
10
|
+
# surrounding context. The methods implemented by this
|
|
11
|
+
# module are available as singleton methods on the {Ryo Ryo}
|
|
12
|
+
# module.
|
|
13
|
+
module Ryo::Enumerable
|
|
14
|
+
##
|
|
15
|
+
# The {#each} method iterates through a Ryo object, and
|
|
16
|
+
# yields two parameters: a key, and a value
|
|
17
|
+
#
|
|
18
|
+
# @example
|
|
19
|
+
# point_a = Ryo(x: 1, y: 2)
|
|
20
|
+
# point_b = Ryo(y: 1)
|
|
21
|
+
# Ryo.each(point_b) { p [_1, _2] }
|
|
22
|
+
# # ["y", 1]
|
|
23
|
+
# # ["y", 2]
|
|
24
|
+
# # ["x", 1]
|
|
25
|
+
#
|
|
26
|
+
# @param (see #each_ryo)
|
|
27
|
+
# @return [<Enumerator, Array>]
|
|
28
|
+
def each(ryo, ancestors: nil)
|
|
29
|
+
return enum_for(:each, ryo) unless block_given?
|
|
30
|
+
each_ryo(ryo, ancestors:) do |_, key, value|
|
|
31
|
+
yield(key, value)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
##
|
|
36
|
+
# The {#each_ryo} method iterates through a Ryo object,
|
|
37
|
+
# and its prototypes. {#each_ryo} yields three parameters:
|
|
38
|
+
# a Ryo object, a key, and a value
|
|
39
|
+
#
|
|
40
|
+
# @example
|
|
41
|
+
# point_a = Ryo(x: 1, y: 2)
|
|
42
|
+
# point_b = Ryo({y: 3}, point_a)
|
|
43
|
+
# Ryo.each_ryo(point_b) { |ryo, key, value| p [ryo, key, value] }
|
|
44
|
+
# # [point_b, "y", 3]
|
|
45
|
+
# # [point_a, "x", 1]
|
|
46
|
+
# # [point_a, "y", 2]
|
|
47
|
+
#
|
|
48
|
+
# @param [<Ryo::BasicObject, Ryo::Object>] ryo
|
|
49
|
+
# @param [Integer] ancestors
|
|
50
|
+
# "ancestors" is an integer that defines the traversal depth
|
|
51
|
+
# of a {Ryo::Enumerable Ryo::Enumerable} method. 0 covers a
|
|
52
|
+
# Ryo object, and none of the prototypes in its prototype
|
|
53
|
+
# chain. 1 covers a Ryo object, and one of the prototypes
|
|
54
|
+
# in its prototype chain - and so on. The default covers
|
|
55
|
+
# the entire prototype chain.
|
|
56
|
+
# @return [<Ryo::BasicObject, Ryo::Object>]
|
|
57
|
+
def each_ryo(ryo, ancestors: nil)
|
|
58
|
+
proto_chain = [ryo, *prototype_chain_of(ryo)]
|
|
59
|
+
ancestors ||= -1
|
|
60
|
+
proto_chain[0..ancestors].each do |ryo|
|
|
61
|
+
properties_of(ryo).each do |key|
|
|
62
|
+
yield(ryo, key, ryo[key])
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
ryo
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
##
|
|
69
|
+
# The {#map} method creates a copy of a Ryo object,
|
|
70
|
+
# and then performs a map operation on the copy and
|
|
71
|
+
# its prototypes
|
|
72
|
+
#
|
|
73
|
+
# @param (see #each_ryo)
|
|
74
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
|
75
|
+
def map(ryo, ancestors: nil, &b)
|
|
76
|
+
map!(Ryo.dup(ryo), ancestors:, &b)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
##
|
|
80
|
+
# The {#map!} method performs an in-place map operation
|
|
81
|
+
# on a Ryo object, and its prototypes
|
|
82
|
+
#
|
|
83
|
+
# @example
|
|
84
|
+
# point = Ryo(x: 2, y: 4)
|
|
85
|
+
# Ryo.map!(point) { _2 * 2 }
|
|
86
|
+
# [point.x, point.y]
|
|
87
|
+
# # => [4, 8]
|
|
88
|
+
#
|
|
89
|
+
# @param (see #each_ryo)
|
|
90
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
|
91
|
+
def map!(ryo, ancestors: nil)
|
|
92
|
+
each_ryo(ryo, ancestors:) do |ryo, key, value|
|
|
93
|
+
ryo[key] = yield(key, value)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
##
|
|
98
|
+
# The {#select} method creates a copy of a Ryo object, and
|
|
99
|
+
# then performs a filter operation on the copy and its
|
|
100
|
+
# prototypes
|
|
101
|
+
#
|
|
102
|
+
# @param (see #each_ryo)
|
|
103
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
|
104
|
+
def select(ryo, ancestors: nil, &b)
|
|
105
|
+
select!(Ryo.dup(ryo), ancestors:, &b)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
##
|
|
109
|
+
# The {#select!} method performs an in-place filter operation
|
|
110
|
+
# on a Ryo object, and its prototypes
|
|
111
|
+
#
|
|
112
|
+
# @example
|
|
113
|
+
# point_a = Ryo(x: 1, y: 2, z: 3)
|
|
114
|
+
# point_b = Ryo({z: 4}, point_a)
|
|
115
|
+
# Ryo.select!(point_b) { |key, value| %w(x y).include?(key) }
|
|
116
|
+
# [point_b.x, point_b.y, point_b.z]
|
|
117
|
+
# # => [1, 2, nil]
|
|
118
|
+
#
|
|
119
|
+
# @param (see #each_ryo)
|
|
120
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
|
121
|
+
def select!(ryo, ancestors: nil)
|
|
122
|
+
each_ryo(ryo, ancestors:) do |ryo, key, value|
|
|
123
|
+
delete(ryo, key) unless yield(key, value)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
##
|
|
128
|
+
# The {#reject} method creates a copy of a Ryo object, and then
|
|
129
|
+
# performs a filter operation on the copy and its prototypes
|
|
130
|
+
#
|
|
131
|
+
# @param (see #each_ryo)
|
|
132
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
|
133
|
+
def reject(ryo, ancestors: nil, &b)
|
|
134
|
+
reject!(Ryo.dup(ryo), ancestors:, &b)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
##
|
|
138
|
+
# The {#reject!} method performs an in-place filter operation
|
|
139
|
+
# on a Ryo object, and its prototypes
|
|
140
|
+
#
|
|
141
|
+
# @example
|
|
142
|
+
# point_a = Ryo(x: 1, y: 2, z: 3)
|
|
143
|
+
# point_b = Ryo({z: 4}, point_a)
|
|
144
|
+
# Ryo.reject!(point_b) { |key, value| value > 2 }
|
|
145
|
+
# [point_b.x, point_b.y, point_b.z]
|
|
146
|
+
# # => [1, 2, nil]
|
|
147
|
+
#
|
|
148
|
+
# @param (see #each_ryo)
|
|
149
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
|
150
|
+
def reject!(ryo, ancestors: nil)
|
|
151
|
+
each_ryo(ryo, ancestors:) do |ryo, key, value|
|
|
152
|
+
delete(ryo, key) if yield(key, value)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
##
|
|
157
|
+
# @param (see #each_ryo)
|
|
158
|
+
# @return [Boolean]
|
|
159
|
+
# Returns true when the given block evaluates to
|
|
160
|
+
# a truthy value for at least one iteration
|
|
161
|
+
def any?(ryo, ancestors: nil)
|
|
162
|
+
each_ryo(ryo, ancestors:) do |_, key, value|
|
|
163
|
+
return true if yield(key, value)
|
|
164
|
+
end
|
|
165
|
+
false
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
##
|
|
169
|
+
# @param (see #each_ryo)
|
|
170
|
+
# @return [Boolean]
|
|
171
|
+
# Returns true when the given block evaluates to a
|
|
172
|
+
# truthy value for every iteration
|
|
173
|
+
def all?(ryo, ancestors: nil)
|
|
174
|
+
each_ryo(ryo, ancestors:) do |_, key, value|
|
|
175
|
+
return false unless yield(key, value)
|
|
176
|
+
end
|
|
177
|
+
true
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
##
|
|
181
|
+
# @example
|
|
182
|
+
# point_a = Ryo(x: 5)
|
|
183
|
+
# point_b = Ryo({y: 10}, point_a)
|
|
184
|
+
# point_c = Ryo({z: 15}, point_b)
|
|
185
|
+
# ryo = Ryo.find(point_c) { |key, value| value == 5 }
|
|
186
|
+
# ryo == point_a # => true
|
|
187
|
+
#
|
|
188
|
+
# @param (see #each_ryo)
|
|
189
|
+
# @return [<Ryo::Object, Ryo::BasicObject>, nil]
|
|
190
|
+
# Returns a Ryo object, or nil
|
|
191
|
+
def find(ryo, ancestors: nil)
|
|
192
|
+
each_ryo(ryo, ancestors:) do |ryo, key, value|
|
|
193
|
+
return ryo if yield(key, value)
|
|
194
|
+
end
|
|
195
|
+
nil
|
|
196
|
+
end
|
|
197
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# The {Ryo::Function Ryo::Function} class represents a Ryo
|
|
5
|
+
# function. The class is usually not used directly but through
|
|
6
|
+
# {Ryo::Keywords#fn Ryo.fn}. A Ryo function has a special relationship
|
|
7
|
+
# with Ryo objects: when a Ryo function is assigned as a property
|
|
8
|
+
# on a Ryo object - the "self" of the function becomes bound to the
|
|
9
|
+
# Ryo object.
|
|
10
|
+
class Ryo::Function
|
|
11
|
+
##
|
|
12
|
+
# @param [Proc] body
|
|
13
|
+
# The body of the function as a block.
|
|
14
|
+
#
|
|
15
|
+
# @return [Ryo::Function]
|
|
16
|
+
# Returns an instance of {Ryo::Function Ryo::Function}.
|
|
17
|
+
def initialize(&body)
|
|
18
|
+
@body = body
|
|
19
|
+
@ryo = nil
|
|
20
|
+
@to_proc = nil
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
##
|
|
24
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
|
25
|
+
# Returns the object that the function's "self" is bound to.
|
|
26
|
+
def receiver
|
|
27
|
+
@ryo
|
|
28
|
+
end
|
|
29
|
+
alias_method :self, :receiver
|
|
30
|
+
|
|
31
|
+
##
|
|
32
|
+
# Change the receiver (self) of the function.
|
|
33
|
+
#
|
|
34
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
|
35
|
+
# A Ryo object.
|
|
36
|
+
#
|
|
37
|
+
# @return [nil]
|
|
38
|
+
def bind!(ryo)
|
|
39
|
+
@ryo = ryo
|
|
40
|
+
@to_proc = nil
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
##
|
|
44
|
+
# Call the function.
|
|
45
|
+
def call(...)
|
|
46
|
+
to_proc.call(...)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
##
|
|
50
|
+
# @return [Proc]
|
|
51
|
+
# Returns the function as a lambda bound to {#receiver}.
|
|
52
|
+
def to_proc
|
|
53
|
+
@to_proc ||= lambda!(@body)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def lambda!(body)
|
|
59
|
+
ryo, lambda = @ryo, nil
|
|
60
|
+
Module.new do
|
|
61
|
+
define_method(:__function__, &body)
|
|
62
|
+
lambda = instance_method(:__function__)
|
|
63
|
+
.bind(ryo)
|
|
64
|
+
.to_proc
|
|
65
|
+
end
|
|
66
|
+
lambda
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# The {Ryo::JSON Ryo::JSON} module provides a number of methods
|
|
5
|
+
# for coercing JSON data into a Ryo object. It must be required
|
|
6
|
+
# separately to Ryo (ie: require "ryo/json"), and the methods of
|
|
7
|
+
# this module are then available on the {Ryo Ryo} module.
|
|
8
|
+
module Ryo::JSON
|
|
9
|
+
require "json"
|
|
10
|
+
extend self
|
|
11
|
+
|
|
12
|
+
##
|
|
13
|
+
# @example
|
|
14
|
+
# Ryo.from_json(path: "/foo/bar/baz.json")
|
|
15
|
+
# Ryo.from_json(string: "[]")
|
|
16
|
+
#
|
|
17
|
+
# @param [String] path
|
|
18
|
+
# The path to a JSON file
|
|
19
|
+
#
|
|
20
|
+
# @param [String] string
|
|
21
|
+
# A blob of JSON
|
|
22
|
+
#
|
|
23
|
+
# @param [Ryo] object
|
|
24
|
+
# {Ryo::Object Ryo::Object}, or {Ryo::BasicObject Ryo::BasicObject}
|
|
25
|
+
# Defaults to {Ryo::Object Ryo::Object}
|
|
26
|
+
#
|
|
27
|
+
# @raise [SystemCallError]
|
|
28
|
+
# Might raise a number of Errno exceptions
|
|
29
|
+
#
|
|
30
|
+
# @return [Ryo::Object, Ryo::BasicObject]
|
|
31
|
+
# Returns a Ryo object
|
|
32
|
+
def from_json(path: nil, string: nil, object: Ryo::Object)
|
|
33
|
+
if path && string
|
|
34
|
+
raise ArgumentError, "Provide a path or string but not both"
|
|
35
|
+
elsif path
|
|
36
|
+
object.from JSON.parse(File.binread(path))
|
|
37
|
+
elsif string
|
|
38
|
+
object.from JSON.parse(string)
|
|
39
|
+
else
|
|
40
|
+
raise ArgumentError, "No path or string provided"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
Ryo.extend(self)
|
|
45
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# The {Ryo::Keywords Ryo::Keywords} module implements Ryo equivalents
|
|
5
|
+
# for some of JavaScript's keywords (eg: the **in** and **delete** operators).
|
|
6
|
+
# The instance methods of this module are available as singleton
|
|
7
|
+
# methods on the {Ryo} module.
|
|
8
|
+
module Ryo::Keywords
|
|
9
|
+
##
|
|
10
|
+
# @example
|
|
11
|
+
# point = Ryo(x: 0, y: 0, print: Ryo.fn { print x, y, "\n" })
|
|
12
|
+
# point.print.()
|
|
13
|
+
#
|
|
14
|
+
# @param [Proc] b
|
|
15
|
+
# The function's body.
|
|
16
|
+
#
|
|
17
|
+
# @return [Ryo::Function]
|
|
18
|
+
# Returns a Ryo function.
|
|
19
|
+
#
|
|
20
|
+
# @see Ryo::Function Ryo::Function
|
|
21
|
+
def fn(&b)
|
|
22
|
+
Ryo::Function.new(&b)
|
|
23
|
+
end
|
|
24
|
+
alias_method :function, :fn
|
|
25
|
+
|
|
26
|
+
##
|
|
27
|
+
# Equivalent to JavaScript's **in** operator
|
|
28
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
|
29
|
+
# A Ryo object
|
|
30
|
+
# @param [<String, #to_s>] property
|
|
31
|
+
# A property name
|
|
32
|
+
# @return [Boolean]
|
|
33
|
+
# Returns true when **property** is a member of **ryo**, or its prototype chain
|
|
34
|
+
def in?(ryo, property)
|
|
35
|
+
return false unless ryo
|
|
36
|
+
property?(ryo, property) || in?(prototype_of(ryo), property)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
##
|
|
40
|
+
# The {#delete} method deletes a property from a Ryo object
|
|
41
|
+
# @see Ryo::Reflect#delete!
|
|
42
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
|
43
|
+
# A Ryo object
|
|
44
|
+
# @param [<String, #to_s>] property
|
|
45
|
+
# A property name
|
|
46
|
+
# @param [Integer] ancestors
|
|
47
|
+
# The number of prototypes to traverse.
|
|
48
|
+
# Defaults to the entire prototype chain.
|
|
49
|
+
# @return [void]
|
|
50
|
+
def delete(ryo, property, ancestors: nil)
|
|
51
|
+
each_ryo(ryo, ancestors:) do
|
|
52
|
+
Ryo.property?(_1, property) ? table_of(_1).delete(property) : nil
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# {Ryo::Object Ryo::Object} is a Ryo object and subclass of
|
|
5
|
+
# Ruby's Object class that can be created by using
|
|
6
|
+
# [Ryo()](https://0x1eef.github.io/x/ryo.rb/top-level-namespace.html#Ryo-instance_method),
|
|
7
|
+
# {Ryo.Object Ryo.Object()}, {Ryo::Object.from Ryo::Object.from},
|
|
8
|
+
# or {Ryo::Object.create Ryo::Object.create}.
|
|
9
|
+
class Ryo::Object
|
|
10
|
+
##
|
|
11
|
+
# @param props (see Ryo::Builder.build)
|
|
12
|
+
# @param prototype (see Ryo::Builder.build)
|
|
13
|
+
# @return [Ryo::Object]
|
|
14
|
+
# Returns an instance of {Ryo::Object Ryo::Object}
|
|
15
|
+
def self.create(props, prototype = nil)
|
|
16
|
+
Ryo::Builder.build(self, props, prototype)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
##
|
|
20
|
+
# Creates a Ryo object by recursively walking a Hash object
|
|
21
|
+
#
|
|
22
|
+
# @param props (see Ryo::Builder.recursive_build)
|
|
23
|
+
# @param prototype (see Ryo::Builder.recursive_build)
|
|
24
|
+
# @return [Ryo::Object]
|
|
25
|
+
# Returns an instance of {Ryo::Object Ryo::Object}.
|
|
26
|
+
def self.from(props, prototype = nil)
|
|
27
|
+
Ryo::Builder.recursive_build(self, props, prototype)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
##
|
|
31
|
+
# Duplicates the internals of a Ryo object
|
|
32
|
+
#
|
|
33
|
+
# @param [Ryo::Object] ryo
|
|
34
|
+
# A Ryo object
|
|
35
|
+
# @return [Ryo::Object]
|
|
36
|
+
# Returns a Ryo object
|
|
37
|
+
def initialize_dup(ryo)
|
|
38
|
+
Ryo.set_table_of(self, Ryo.table_of(ryo).dup)
|
|
39
|
+
Ryo.extend!(self, Ryo)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
##
|
|
44
|
+
# @example
|
|
45
|
+
# point = Ryo::Object(x: 0, y: 0)
|
|
46
|
+
# p [point.x, point.y] # => [0, 0]
|
|
47
|
+
#
|
|
48
|
+
# @param props (see Ryo::Builder.build)
|
|
49
|
+
# @param prototype (see Ryo::Builder.build)
|
|
50
|
+
# @return [Ryo::Object]
|
|
51
|
+
# Returns an instance of {Ryo::Object Ryo::Object}
|
|
52
|
+
def Ryo.Object(props, prototype = nil)
|
|
53
|
+
Ryo::Object.create(props, prototype)
|
|
54
|
+
end
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# The {Ryo::Reflect Ryo::Reflect} module mirrors
|
|
5
|
+
# JavaScript's [`Relfect` object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect),
|
|
6
|
+
# and some of the static methods on JavaScript's
|
|
7
|
+
# [`Object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)
|
|
8
|
+
# as well.
|
|
9
|
+
#
|
|
10
|
+
# {Ryo::Reflect Ryo::Reflect} also implements Ryo-specific
|
|
11
|
+
# reflection features. The instance methods of this module
|
|
12
|
+
# are available as singleton methods on the {Ryo Ryo}
|
|
13
|
+
# module.
|
|
14
|
+
module Ryo::Reflect
|
|
15
|
+
extend self
|
|
16
|
+
|
|
17
|
+
##
|
|
18
|
+
# @group JavaScript equivalents (Reflect)
|
|
19
|
+
|
|
20
|
+
##
|
|
21
|
+
# Equivalent to JavaScript's `Reflect.getPrototypeOf`
|
|
22
|
+
#
|
|
23
|
+
# @param [Ryo] ryo
|
|
24
|
+
# A Ryo object.
|
|
25
|
+
#
|
|
26
|
+
# @return [Ryo, nil]
|
|
27
|
+
# Returns the prototype of the *ryo* object.
|
|
28
|
+
def prototype_of(ryo)
|
|
29
|
+
kernel(:instance_variable_get)
|
|
30
|
+
.bind_call(ryo, :@_proto)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
##
|
|
34
|
+
# Equivalent to JavaScript's `Reflect.setPrototypeOf`
|
|
35
|
+
#
|
|
36
|
+
# @param [Ryo] ryo
|
|
37
|
+
# A Ryo object.
|
|
38
|
+
#
|
|
39
|
+
# @param [Ryo] prototype
|
|
40
|
+
# The prototype to assign to *ryo*.
|
|
41
|
+
#
|
|
42
|
+
# @return [nil]
|
|
43
|
+
def set_prototype_of(ryo, prototype)
|
|
44
|
+
kernel(:instance_variable_set)
|
|
45
|
+
.bind_call(ryo, :@_proto, prototype)
|
|
46
|
+
nil
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
##
|
|
50
|
+
# Equivalent to JavaScript's `Reflect.defineProperty`
|
|
51
|
+
#
|
|
52
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
|
53
|
+
# A Ryo object
|
|
54
|
+
# @param [<String, #to_s>] property
|
|
55
|
+
# The name of a property
|
|
56
|
+
# @param [Object, BasicObject] value
|
|
57
|
+
# The property's value
|
|
58
|
+
# @return [void]
|
|
59
|
+
def define_property(ryo, property, value)
|
|
60
|
+
table, property = table_of(ryo), property.to_s
|
|
61
|
+
kernel(:tap).bind_call(value) { _1.bind!(ryo) if function?(_1) }
|
|
62
|
+
table[property] = value
|
|
63
|
+
# Define setter
|
|
64
|
+
if !setter_defined?(ryo, property) && property[-1] != "?"
|
|
65
|
+
define_method!(ryo, "#{property}=") { ryo[property] = _1 }
|
|
66
|
+
end
|
|
67
|
+
# Define getter
|
|
68
|
+
return if getter_defined?(ryo, property)
|
|
69
|
+
define_method!(ryo, property) { |*args, &b|
|
|
70
|
+
(args.empty? && b.nil?) ? ryo[property] :
|
|
71
|
+
super(*args, &b)
|
|
72
|
+
}
|
|
73
|
+
nil
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
##
|
|
77
|
+
# Equivalent to JavaScript's `Reflect.ownKeys`, and
|
|
78
|
+
# JavaScript's `Object.keys`
|
|
79
|
+
#
|
|
80
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
|
81
|
+
# A Ryo object
|
|
82
|
+
# @return [Array<String>]
|
|
83
|
+
# Returns the properties defined on a Ryo object
|
|
84
|
+
def properties_of(ryo)
|
|
85
|
+
table_of(ryo).keys
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# @endgroup
|
|
89
|
+
|
|
90
|
+
##
|
|
91
|
+
# @group JavaScript equivalents (Object)
|
|
92
|
+
|
|
93
|
+
##
|
|
94
|
+
# Equivalent to JavaScript's `Object.hasOwn`,
|
|
95
|
+
# and `Object.prototype.hasOwnProperty`.
|
|
96
|
+
#
|
|
97
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
|
98
|
+
# A Ryo object
|
|
99
|
+
# @param [<String, #to_s>] property
|
|
100
|
+
# The name of a property
|
|
101
|
+
# @return [Boolean]
|
|
102
|
+
# Returns true when the property is a member of a Ryo object
|
|
103
|
+
def property?(ryo, property)
|
|
104
|
+
table_of(ryo).key?(property.to_s)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
##
|
|
108
|
+
# Equivalent to JavaScript's `Object.assign`.
|
|
109
|
+
#
|
|
110
|
+
# @param [Ryo, Hash, #to_hash] target
|
|
111
|
+
# The target object
|
|
112
|
+
# @param [Ryo, Hash, #to_hash] sources
|
|
113
|
+
# A variable number of source objects that
|
|
114
|
+
# will be merged with the target object
|
|
115
|
+
# @return [Ryo]
|
|
116
|
+
# Returns the modified target object.
|
|
117
|
+
def assign(target, *sources)
|
|
118
|
+
sources.each do |source|
|
|
119
|
+
to_hash(source).each { target[_1.to_s] = _2 }
|
|
120
|
+
end
|
|
121
|
+
target
|
|
122
|
+
end
|
|
123
|
+
# @endgroup
|
|
124
|
+
|
|
125
|
+
##
|
|
126
|
+
# @group Ryo-specific
|
|
127
|
+
|
|
128
|
+
##
|
|
129
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
|
130
|
+
# A Ryo object
|
|
131
|
+
# @return [Array<Ryo::Object, Ryo::BasicObject>]
|
|
132
|
+
# Returns the prototype chain of a Ryo object
|
|
133
|
+
def prototype_chain_of(ryo)
|
|
134
|
+
prototypes = []
|
|
135
|
+
loop do
|
|
136
|
+
ryo = prototype_of(ryo)
|
|
137
|
+
break unless ryo
|
|
138
|
+
prototypes.push(ryo)
|
|
139
|
+
end
|
|
140
|
+
prototypes
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
##
|
|
144
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
|
145
|
+
# A Ryo object
|
|
146
|
+
# @param [Boolean] recursive
|
|
147
|
+
# When true, nested Ryo objects are replaced by
|
|
148
|
+
# their table as well
|
|
149
|
+
# @return [Hash]
|
|
150
|
+
# Returns the table of a Ryo object
|
|
151
|
+
def table_of(ryo, recursive: false)
|
|
152
|
+
table = kernel(:instance_variable_get).bind_call(ryo, :@_table)
|
|
153
|
+
if recursive
|
|
154
|
+
table.each do |key, value|
|
|
155
|
+
if ryo?(value)
|
|
156
|
+
table[key] = table_of(value, recursive:)
|
|
157
|
+
elsif value.respond_to?(:each)
|
|
158
|
+
table[key] = value.respond_to?(:each_pair) ?
|
|
159
|
+
value : value.map { table_of(_1, recursive:) }
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
table
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
##
|
|
167
|
+
# Sets the table of a Ryo object
|
|
168
|
+
#
|
|
169
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
|
170
|
+
# A Ryo object
|
|
171
|
+
# @param [Hash] table
|
|
172
|
+
# The table
|
|
173
|
+
# @return [nil]
|
|
174
|
+
def set_table_of(ryo, table)
|
|
175
|
+
kernel(:instance_variable_set)
|
|
176
|
+
.bind_call(ryo, :@_table, table)
|
|
177
|
+
nil
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
##
|
|
181
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
|
182
|
+
# A Ryo object
|
|
183
|
+
# @param [<String, Symbol>] method
|
|
184
|
+
# The name of a method
|
|
185
|
+
# @param [::Object, ::BasicObject] args
|
|
186
|
+
# Zero or more method arguments
|
|
187
|
+
# @param [Proc] b
|
|
188
|
+
# An optional block
|
|
189
|
+
# @return [::Object, ::BasicObject]
|
|
190
|
+
def call_method(ryo, method, *args, &b)
|
|
191
|
+
kernel(:__send__)
|
|
192
|
+
.bind_call(ryo, method, *args, &b)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
##
|
|
196
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
|
197
|
+
# A Ryo object
|
|
198
|
+
# @return [Class]
|
|
199
|
+
# Returns the class of a Ryo object
|
|
200
|
+
def class_of(ryo)
|
|
201
|
+
kernel(:class).bind_call(ryo)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
##
|
|
205
|
+
# @param [Ryo::Function, Object, BasicObject] obj
|
|
206
|
+
# An object
|
|
207
|
+
# @return [Boolean]
|
|
208
|
+
# Returns true when given a Ryo function
|
|
209
|
+
def function?(obj)
|
|
210
|
+
Ryo::Function === obj
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
##
|
|
214
|
+
# @param [Ryo::Function, Object, BasicObject] obj
|
|
215
|
+
# An object
|
|
216
|
+
# @return [Boolean]
|
|
217
|
+
# Returns true when given a Ryo memo
|
|
218
|
+
def memo?(obj)
|
|
219
|
+
Ryo::Memo === obj
|
|
220
|
+
end
|
|
221
|
+
alias_method :lazy?, :memo?
|
|
222
|
+
|
|
223
|
+
##
|
|
224
|
+
# @example
|
|
225
|
+
# Ryo.ryo?(Ryo::Object(x: 5, y: 12)) # => true
|
|
226
|
+
# Ryo.ryo?(Ryo::BasicObject(x: 10, y: 20)) # => true
|
|
227
|
+
# Ryo.ryo?(Object.new) # => false
|
|
228
|
+
#
|
|
229
|
+
# @param [Object, BasicObject] obj
|
|
230
|
+
# An object
|
|
231
|
+
# @return [Boolean]
|
|
232
|
+
# Returns true when given a Ryo object
|
|
233
|
+
def ryo?(obj)
|
|
234
|
+
Ryo === obj
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
##
|
|
238
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo1
|
|
239
|
+
# A Ryo object
|
|
240
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo2
|
|
241
|
+
# A Ryo object
|
|
242
|
+
# @return [Boolean]
|
|
243
|
+
# Returns true when the two Ryo objects are strictly equal
|
|
244
|
+
def equal?(ryo1, ryo2)
|
|
245
|
+
kernel(:equal?).bind_call(ryo1, ryo2)
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
##
|
|
249
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
|
250
|
+
# A Ryo object
|
|
251
|
+
# @return [String]
|
|
252
|
+
# Returns a String representation of a Ryo object
|
|
253
|
+
def inspect_object(ryo)
|
|
254
|
+
format(
|
|
255
|
+
"#<Ryo object=%{object} proto=%{proto} table=%{table}>",
|
|
256
|
+
object: Object.instance_method(:to_s).bind_call(ryo),
|
|
257
|
+
proto: prototype_of(ryo).inspect,
|
|
258
|
+
table: table_of(ryo).inspect
|
|
259
|
+
)
|
|
260
|
+
end
|
|
261
|
+
# @endgroup
|
|
262
|
+
|
|
263
|
+
include Ryo::Utils
|
|
264
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# The {Ryo::Utils Ryo::Utils} module provides utility
|
|
5
|
+
# methods that are internal to Ryo. This module
|
|
6
|
+
# and its methods should not be used directly.
|
|
7
|
+
# @api private
|
|
8
|
+
module Ryo::Utils
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
|
13
|
+
# A Ryo object
|
|
14
|
+
# @param [<String, Symbol>] method
|
|
15
|
+
# The name of a method
|
|
16
|
+
# @param [Proc] b
|
|
17
|
+
# The method's implementation
|
|
18
|
+
def define_method!(ryo, method, &b)
|
|
19
|
+
kernel(:define_singleton_method)
|
|
20
|
+
.bind_call(ryo, method, &b)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
##
|
|
24
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
|
25
|
+
# A Ryo object
|
|
26
|
+
# @param [<String, #to_s>] property
|
|
27
|
+
# The name of a property
|
|
28
|
+
# @return [Boolean]
|
|
29
|
+
# Returns true for a Ryo property that has a
|
|
30
|
+
# corresponding getter method implemented by Ryo
|
|
31
|
+
def getter_defined?(ryo, property)
|
|
32
|
+
path = kernel(:method)
|
|
33
|
+
.bind_call(ryo, property)
|
|
34
|
+
.source_location
|
|
35
|
+
&.dig(0)
|
|
36
|
+
path ? File.dirname(path) == File.dirname(__FILE__) : false
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
##
|
|
40
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
|
41
|
+
# A Ryo object
|
|
42
|
+
# @param [<String, #to_s>] property
|
|
43
|
+
# The name of a property
|
|
44
|
+
# @return [Boolean]
|
|
45
|
+
# Returns true for a Ryo property that has a
|
|
46
|
+
# corresponding setter method implemented by Ryo
|
|
47
|
+
def setter_defined?(ryo, property)
|
|
48
|
+
getter_defined?(ryo, "#{property}=")
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def merge!(obj1, obj2)
|
|
52
|
+
obj1, obj2 = to_hash(obj1), to_hash(obj2)
|
|
53
|
+
obj2.each { obj1[_1.to_s] = _2 }
|
|
54
|
+
obj1
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def to_hash(obj)
|
|
58
|
+
if ryo?(obj)
|
|
59
|
+
table_of(obj)
|
|
60
|
+
else
|
|
61
|
+
Hash.try_convert(obj)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def kernel(name)
|
|
66
|
+
Module.instance_method(name)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# The {Ryo::YAML Ryo::YAML} module provides a number of methods
|
|
5
|
+
# for coercing YAML data into a Ryo object. It must be required
|
|
6
|
+
# separately to Ryo (ie: require "ryo/yaml"), and the methods of
|
|
7
|
+
# this module are then available on the {Ryo Ryo} module.
|
|
8
|
+
module Ryo::YAML
|
|
9
|
+
require "yaml"
|
|
10
|
+
extend self
|
|
11
|
+
|
|
12
|
+
##
|
|
13
|
+
# @example
|
|
14
|
+
# Ryo.from_yaml(path: "/foo/bar/baz.yaml")
|
|
15
|
+
# Ryo.from_yaml(string: "---\nfoo: bar\n")
|
|
16
|
+
#
|
|
17
|
+
# @param [String] path
|
|
18
|
+
# The path to a YAML file
|
|
19
|
+
#
|
|
20
|
+
# @param [String] string
|
|
21
|
+
# A blob of YAML
|
|
22
|
+
#
|
|
23
|
+
# @param [Ryo] object
|
|
24
|
+
# {Ryo::Object Ryo::Object}, or {Ryo::BasicObject Ryo::BasicObject}
|
|
25
|
+
# Defaults to {Ryo::Object Ryo::Object}
|
|
26
|
+
#
|
|
27
|
+
# @raise [SystemCallError]
|
|
28
|
+
# Might raise a number of Errno exceptions
|
|
29
|
+
#
|
|
30
|
+
# @return [Ryo::Object, Ryo::BasicObject]
|
|
31
|
+
# Returns a Ryo object
|
|
32
|
+
def from_yaml(path: nil, string: nil, object: Ryo::Object)
|
|
33
|
+
if path && string
|
|
34
|
+
raise ArgumentError, "Provide a path or string but not both"
|
|
35
|
+
elsif path
|
|
36
|
+
object.from YAML.load_file(path)
|
|
37
|
+
elsif string
|
|
38
|
+
object.from YAML.load(string)
|
|
39
|
+
else
|
|
40
|
+
raise ArgumentError, "No path or string provided"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
Ryo.extend(self)
|
|
45
|
+
end
|
|
@@ -0,0 +1,195 @@
|
|
|
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/utils"
|
|
19
|
+
require_relative "ryo/reflect"
|
|
20
|
+
require_relative "ryo/keywords"
|
|
21
|
+
require_relative "ryo/builder"
|
|
22
|
+
require_relative "ryo/basic_object"
|
|
23
|
+
require_relative "ryo/object"
|
|
24
|
+
require_relative "ryo/function"
|
|
25
|
+
require_relative "ryo/memo"
|
|
26
|
+
require_relative "ryo/enumerable"
|
|
27
|
+
|
|
28
|
+
extend Ryo::Reflect
|
|
29
|
+
extend Ryo::Keywords
|
|
30
|
+
extend Ryo::Enumerable
|
|
31
|
+
|
|
32
|
+
##
|
|
33
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
|
34
|
+
# A Ryo object
|
|
35
|
+
# @param [Module] mod
|
|
36
|
+
# The module to extend a Ryo object with
|
|
37
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
|
38
|
+
# Returns an extended Ryo object
|
|
39
|
+
def self.extend!(ryo, mod)
|
|
40
|
+
kernel(:extend).bind_call(ryo, mod)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
##
|
|
44
|
+
# Duplicates a Ryo object, and its prototype(s).
|
|
45
|
+
#
|
|
46
|
+
# @param [<Ryo::Object, Ryo::BasicObject>] ryo
|
|
47
|
+
# A Ryo object
|
|
48
|
+
# @return [<Ryo::Object, Ryo::BasicObject>]
|
|
49
|
+
# Returns a duplicated Ryo object
|
|
50
|
+
def self.dup(ryo)
|
|
51
|
+
duplicate = extend!(
|
|
52
|
+
kernel(:dup).bind_call(ryo),
|
|
53
|
+
self
|
|
54
|
+
)
|
|
55
|
+
if proto = prototype_of(duplicate)
|
|
56
|
+
set_prototype_of(duplicate, dup(proto))
|
|
57
|
+
end
|
|
58
|
+
duplicate
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
##
|
|
62
|
+
# Creates a memoized Ryo value
|
|
63
|
+
#
|
|
64
|
+
# @param [Proc] b
|
|
65
|
+
# A Proc that is memoized after being accessed for the first time
|
|
66
|
+
# @return [Ryo::Memo]
|
|
67
|
+
# Returns an instance of {Ryo::Memo Ryo::Memo}
|
|
68
|
+
def self.memo(&b)
|
|
69
|
+
Ryo::Memo.new(&b)
|
|
70
|
+
end
|
|
71
|
+
class << Ryo
|
|
72
|
+
alias_method :lazy, :memo
|
|
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
|
+
# @return [Ryo::Object]
|
|
81
|
+
# Returns an instance of {Ryo::Object Ryo::Object}
|
|
82
|
+
def self.from(props, prototype = nil)
|
|
83
|
+
Ryo::Object.from(props, prototype)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
##
|
|
87
|
+
# @return [<Ryo::Object, Ryo::BasicObject>, nil]
|
|
88
|
+
# Returns the prototype of self, or nil if self has no prototype
|
|
89
|
+
def __proto__
|
|
90
|
+
@_proto
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
##
|
|
94
|
+
# @note
|
|
95
|
+
# This method will first look for a property on self,
|
|
96
|
+
# and if it is not found then it will forward the query
|
|
97
|
+
# onto `Ryo#__proto__`
|
|
98
|
+
# @param [String] property
|
|
99
|
+
# The name of a property
|
|
100
|
+
# @return [<Object, BasicObject>, nil]
|
|
101
|
+
# Returns the property's value, or nil
|
|
102
|
+
def [](property)
|
|
103
|
+
property = property.to_s
|
|
104
|
+
if Ryo.property?(self, property)
|
|
105
|
+
v = @_table[property]
|
|
106
|
+
Ryo.memo?(v) ? self[property] = v.call : v
|
|
107
|
+
else
|
|
108
|
+
return unless @_proto
|
|
109
|
+
Ryo.call_method(@_proto, property)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
##
|
|
114
|
+
# Assign a property
|
|
115
|
+
#
|
|
116
|
+
# @param [String] property
|
|
117
|
+
# The name of a property
|
|
118
|
+
# @param [<Object,BasicObject>] value
|
|
119
|
+
# @return [void]
|
|
120
|
+
def []=(property, value)
|
|
121
|
+
Ryo.define_property(self, property.to_s, value)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
##
|
|
125
|
+
# @param [<Ryo::Object, Ryo::BasicObject>, Hash, #to_h] other
|
|
126
|
+
# @return [Boolean]
|
|
127
|
+
# Returns true **other** is equal to self
|
|
128
|
+
def ==(other)
|
|
129
|
+
if Ryo.ryo?(other)
|
|
130
|
+
@_table == Ryo.table_of(other)
|
|
131
|
+
else
|
|
132
|
+
other = Hash.try_convert(other)
|
|
133
|
+
return false unless other
|
|
134
|
+
@_table == other.map { [_1.to_s, _2] }.to_h
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
alias_method :eql?, :==
|
|
138
|
+
|
|
139
|
+
##
|
|
140
|
+
# @return [String]
|
|
141
|
+
# Returns a String representation of a Ryo object
|
|
142
|
+
def inspect
|
|
143
|
+
Ryo.inspect_object(self)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
##
|
|
147
|
+
# @return [Hash]
|
|
148
|
+
# Returns the lookup table of a Ryo object
|
|
149
|
+
def to_h
|
|
150
|
+
Ryo.table_of(self, recursive: true)
|
|
151
|
+
end
|
|
152
|
+
alias_method :to_hash, :to_h
|
|
153
|
+
|
|
154
|
+
##
|
|
155
|
+
# @private
|
|
156
|
+
def pretty_print(q)
|
|
157
|
+
q.text(inspect)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
##
|
|
161
|
+
# @private
|
|
162
|
+
def respond_to?(property, include_all = false)
|
|
163
|
+
respond_to_missing?(property, include_all)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
##
|
|
167
|
+
# @private
|
|
168
|
+
def respond_to_missing?(property, include_all = false)
|
|
169
|
+
true
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
##
|
|
173
|
+
# @private
|
|
174
|
+
def method_missing(name, *args, &b)
|
|
175
|
+
property = name.to_s
|
|
176
|
+
if property[-1] == "="
|
|
177
|
+
property = property[0..-2]
|
|
178
|
+
self[property] = args.first
|
|
179
|
+
elsif Ryo.property?(self, property)
|
|
180
|
+
self[property]
|
|
181
|
+
elsif @_proto
|
|
182
|
+
Ryo.call_method(@_proto, name, *args, &b)
|
|
183
|
+
.tap { _1.bind!(self) if Ryo.function?(_1) }
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
##
|
|
189
|
+
# @param props (see Ryo::Builder.build)
|
|
190
|
+
# @param prototype (see Ryo::Builder.build)
|
|
191
|
+
# @return [Ryo::Object]
|
|
192
|
+
# Returns a Ryo object
|
|
193
|
+
def Ryo(props, prototype = nil)
|
|
194
|
+
Ryo::Object.create(props, prototype)
|
|
195
|
+
end
|
data/share/quran-audio/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
v0.4.
|
|
1
|
+
v0.4.2
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: quran-audio
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- '0x1eef'
|
|
@@ -119,6 +119,21 @@ files:
|
|
|
119
119
|
- LICENSE
|
|
120
120
|
- README.md
|
|
121
121
|
- bin/quran-audio
|
|
122
|
+
- bundle/io-line.rb/lib/io/line.rb
|
|
123
|
+
- bundle/io-line.rb/lib/io/line/multiple.rb
|
|
124
|
+
- bundle/ryo.rb/lib/ryo.rb
|
|
125
|
+
- bundle/ryo.rb/lib/ryo/basic_object.rb
|
|
126
|
+
- bundle/ryo.rb/lib/ryo/builder.rb
|
|
127
|
+
- bundle/ryo.rb/lib/ryo/enumerable.rb
|
|
128
|
+
- bundle/ryo.rb/lib/ryo/function.rb
|
|
129
|
+
- bundle/ryo.rb/lib/ryo/json.rb
|
|
130
|
+
- bundle/ryo.rb/lib/ryo/keywords.rb
|
|
131
|
+
- bundle/ryo.rb/lib/ryo/memo.rb
|
|
132
|
+
- bundle/ryo.rb/lib/ryo/object.rb
|
|
133
|
+
- bundle/ryo.rb/lib/ryo/reflect.rb
|
|
134
|
+
- bundle/ryo.rb/lib/ryo/utils.rb
|
|
135
|
+
- bundle/ryo.rb/lib/ryo/version.rb
|
|
136
|
+
- bundle/ryo.rb/lib/ryo/yaml.rb
|
|
122
137
|
- lib/quran/audio.rb
|
|
123
138
|
- lib/quran/audio/command.rb
|
|
124
139
|
- lib/quran/audio/command/ls.rb
|