quran-audio 0.4.1 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fc399ffb1f9b7ca57d21c91e2efea8044d2f3f36d48b42263ad3198a1648523a
4
- data.tar.gz: 8123974f8d534c884035802c1698e4fcea0ed1c60df2f3b5613cff26c01cbb30
3
+ metadata.gz: f31510aaf2b2ac45001870411b82eb1e1ff7c8103cdbebb4f9b92268906b4cfb
4
+ data.tar.gz: 6c54cbdf7ed5493fcb9cc0cf0e84305adae279c2433d5f1e6204ac9ba9af9b38
5
5
  SHA512:
6
- metadata.gz: 8bedbadb87f13cca4c13c7150fb9ff1b9c5cb6ab5b5c77127495c942ba6d9c83734887de13e0a2abfcfa246e9509b44d573b834933f62212be1da04aba33af12
7
- data.tar.gz: 3b5f5404f99cc8d64d817326cc747c36356caf76fabe9fb8c99962effb6fac5e3a3a28a5b086c9903b2df4ccf1a185a1ade01ed0417f9386685827f0284d5e19
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,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Ryo::Memo < Ryo::Function
4
+ 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,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ryo
4
+ VERSION = "0.5.6"
5
+ 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
@@ -1 +1 @@
1
- v0.4.1
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.1
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