liquid 3.0.6 → 4.0.0.rc1
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/History.md +89 -58
- data/{MIT-LICENSE → LICENSE} +0 -0
- data/lib/liquid.rb +7 -6
- data/lib/liquid/block.rb +31 -124
- data/lib/liquid/block_body.rb +54 -57
- data/lib/liquid/condition.rb +23 -22
- data/lib/liquid/context.rb +50 -42
- data/lib/liquid/document.rb +19 -9
- data/lib/liquid/drop.rb +12 -13
- data/lib/liquid/errors.rb +16 -17
- data/lib/liquid/expression.rb +15 -3
- data/lib/liquid/extensions.rb +7 -7
- data/lib/liquid/file_system.rb +3 -3
- data/lib/liquid/forloop_drop.rb +42 -0
- data/lib/liquid/i18n.rb +5 -5
- data/lib/liquid/interrupts.rb +1 -2
- data/lib/liquid/lexer.rb +6 -4
- data/lib/liquid/locales/en.yml +3 -1
- data/lib/liquid/parse_context.rb +37 -0
- data/lib/liquid/parser_switching.rb +4 -4
- data/lib/liquid/profiler.rb +18 -19
- data/lib/liquid/profiler/hooks.rb +7 -7
- data/lib/liquid/range_lookup.rb +16 -1
- data/lib/liquid/resource_limits.rb +23 -0
- data/lib/liquid/standardfilters.rb +101 -56
- data/lib/liquid/strainer.rb +4 -5
- data/lib/liquid/tablerowloop_drop.rb +62 -0
- data/lib/liquid/tag.rb +9 -8
- data/lib/liquid/tags/assign.rb +5 -4
- data/lib/liquid/tags/break.rb +0 -3
- data/lib/liquid/tags/capture.rb +1 -1
- data/lib/liquid/tags/case.rb +19 -12
- data/lib/liquid/tags/comment.rb +2 -2
- data/lib/liquid/tags/cycle.rb +6 -6
- data/lib/liquid/tags/decrement.rb +1 -4
- data/lib/liquid/tags/for.rb +93 -75
- data/lib/liquid/tags/if.rb +49 -44
- data/lib/liquid/tags/ifchanged.rb +0 -2
- data/lib/liquid/tags/include.rb +60 -52
- data/lib/liquid/tags/raw.rb +26 -4
- data/lib/liquid/tags/table_row.rb +12 -30
- data/lib/liquid/tags/unless.rb +3 -4
- data/lib/liquid/template.rb +23 -50
- data/lib/liquid/tokenizer.rb +31 -0
- data/lib/liquid/utils.rb +48 -8
- data/lib/liquid/variable.rb +46 -45
- data/lib/liquid/variable_lookup.rb +3 -3
- data/lib/liquid/version.rb +1 -1
- data/test/integration/assign_test.rb +8 -8
- data/test/integration/blank_test.rb +14 -14
- data/test/integration/context_test.rb +2 -2
- data/test/integration/document_test.rb +19 -0
- data/test/integration/drop_test.rb +42 -40
- data/test/integration/error_handling_test.rb +64 -45
- data/test/integration/filter_test.rb +60 -20
- data/test/integration/output_test.rb +26 -27
- data/test/integration/parsing_quirks_test.rb +15 -13
- data/test/integration/render_profiling_test.rb +20 -20
- data/test/integration/security_test.rb +5 -7
- data/test/integration/standard_filter_test.rb +119 -37
- data/test/integration/tags/break_tag_test.rb +1 -2
- data/test/integration/tags/continue_tag_test.rb +0 -1
- data/test/integration/tags/for_tag_test.rb +133 -98
- data/test/integration/tags/if_else_tag_test.rb +75 -77
- data/test/integration/tags/include_tag_test.rb +23 -30
- data/test/integration/tags/increment_tag_test.rb +10 -11
- data/test/integration/tags/raw_tag_test.rb +7 -1
- data/test/integration/tags/standard_tag_test.rb +121 -122
- data/test/integration/tags/statements_test.rb +3 -5
- data/test/integration/tags/table_row_test.rb +20 -19
- data/test/integration/tags/unless_else_tag_test.rb +6 -6
- data/test/integration/template_test.rb +91 -45
- data/test/integration/variable_test.rb +23 -13
- data/test/test_helper.rb +33 -5
- data/test/unit/block_unit_test.rb +6 -5
- data/test/unit/condition_unit_test.rb +82 -77
- data/test/unit/context_unit_test.rb +48 -57
- data/test/unit/file_system_unit_test.rb +3 -3
- data/test/unit/i18n_unit_test.rb +2 -2
- data/test/unit/lexer_unit_test.rb +11 -8
- data/test/unit/parser_unit_test.rb +2 -2
- data/test/unit/regexp_unit_test.rb +1 -1
- data/test/unit/strainer_unit_test.rb +13 -2
- data/test/unit/tag_unit_test.rb +7 -2
- data/test/unit/tags/case_tag_unit_test.rb +1 -1
- data/test/unit/tags/for_tag_unit_test.rb +2 -2
- data/test/unit/tags/if_tag_unit_test.rb +1 -1
- data/test/unit/template_unit_test.rb +6 -5
- data/test/unit/tokenizer_unit_test.rb +24 -7
- data/test/unit/variable_unit_test.rb +60 -43
- metadata +44 -41
- data/lib/liquid/module_ex.rb +0 -62
- data/lib/liquid/token.rb +0 -18
- data/test/unit/module_ex_unit_test.rb +0 -87
data/lib/liquid/condition.rb
CHANGED
@@ -3,21 +3,26 @@ module Liquid
|
|
3
3
|
#
|
4
4
|
# Example:
|
5
5
|
#
|
6
|
-
# c = Condition.new(
|
6
|
+
# c = Condition.new(1, '==', 1)
|
7
7
|
# c.evaluate #=> true
|
8
8
|
#
|
9
9
|
class Condition #:nodoc:
|
10
10
|
@@operators = {
|
11
|
-
'=='.freeze =>
|
12
|
-
'!='.freeze =>
|
13
|
-
'<>'.freeze =>
|
11
|
+
'=='.freeze => ->(cond, left, right) { cond.send(:equal_variables, left, right) },
|
12
|
+
'!='.freeze => ->(cond, left, right) { !cond.send(:equal_variables, left, right) },
|
13
|
+
'<>'.freeze => ->(cond, left, right) { !cond.send(:equal_variables, left, right) },
|
14
14
|
'<'.freeze => :<,
|
15
15
|
'>'.freeze => :>,
|
16
16
|
'>='.freeze => :>=,
|
17
17
|
'<='.freeze => :<=,
|
18
|
-
'contains'.freeze => lambda
|
19
|
-
left && right && left.respond_to?(:include?)
|
20
|
-
|
18
|
+
'contains'.freeze => lambda do |cond, left, right|
|
19
|
+
if left && right && left.respond_to?(:include?)
|
20
|
+
right = right.to_s if left.is_a?(String)
|
21
|
+
left.include?(right)
|
22
|
+
else
|
23
|
+
false
|
24
|
+
end
|
25
|
+
end
|
21
26
|
}
|
22
27
|
|
23
28
|
def self.operators
|
@@ -73,17 +78,17 @@ module Liquid
|
|
73
78
|
private
|
74
79
|
|
75
80
|
def equal_variables(left, right)
|
76
|
-
if left.is_a?(
|
77
|
-
if right.respond_to?(left)
|
78
|
-
return right.send(left.
|
81
|
+
if left.is_a?(Liquid::Expression::MethodLiteral)
|
82
|
+
if right.respond_to?(left.method_name)
|
83
|
+
return right.send(left.method_name)
|
79
84
|
else
|
80
85
|
return nil
|
81
86
|
end
|
82
87
|
end
|
83
88
|
|
84
|
-
if right.is_a?(
|
85
|
-
if left.respond_to?(right)
|
86
|
-
return left.send(right.
|
89
|
+
if right.is_a?(Liquid::Expression::MethodLiteral)
|
90
|
+
if left.respond_to?(right.method_name)
|
91
|
+
return left.send(right.method_name)
|
87
92
|
else
|
88
93
|
return nil
|
89
94
|
end
|
@@ -96,36 +101,32 @@ module Liquid
|
|
96
101
|
# If the operator is empty this means that the decision statement is just
|
97
102
|
# a single variable. We can just poll this variable from the context and
|
98
103
|
# return this as the result.
|
99
|
-
return context
|
104
|
+
return context.evaluate(left) if op.nil?
|
100
105
|
|
101
|
-
left = context
|
102
|
-
right = context
|
106
|
+
left = context.evaluate(left)
|
107
|
+
right = context.evaluate(right)
|
103
108
|
|
104
109
|
operation = self.class.operators[op] || raise(Liquid::ArgumentError.new("Unknown operator #{op}"))
|
105
110
|
|
106
111
|
if operation.respond_to?(:call)
|
107
112
|
operation.call(self, left, right)
|
108
|
-
elsif left.respond_to?(operation)
|
113
|
+
elsif left.respond_to?(operation) && right.respond_to?(operation)
|
109
114
|
begin
|
110
115
|
left.send(operation, right)
|
111
116
|
rescue ::ArgumentError => e
|
112
117
|
raise Liquid::ArgumentError.new(e.message)
|
113
118
|
end
|
114
|
-
else
|
115
|
-
nil
|
116
119
|
end
|
117
120
|
end
|
118
121
|
end
|
119
122
|
|
120
|
-
|
121
123
|
class ElseCondition < Condition
|
122
124
|
def else?
|
123
125
|
true
|
124
126
|
end
|
125
127
|
|
126
|
-
def evaluate(
|
128
|
+
def evaluate(_context)
|
127
129
|
true
|
128
130
|
end
|
129
131
|
end
|
130
|
-
|
131
132
|
end
|
data/lib/liquid/context.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module Liquid
|
2
|
-
|
3
2
|
# Context keeps the variable stack and resolves variables, as well as keywords
|
4
3
|
#
|
5
4
|
# context['variable'] = 'testing'
|
@@ -14,41 +13,30 @@ module Liquid
|
|
14
13
|
# context['bob'] #=> nil class Context
|
15
14
|
class Context
|
16
15
|
attr_reader :scopes, :errors, :registers, :environments, :resource_limits
|
17
|
-
attr_accessor :exception_handler
|
16
|
+
attr_accessor :exception_handler, :template_name, :partial, :global_filter
|
18
17
|
|
19
18
|
def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = nil)
|
20
19
|
@environments = [environments].flatten
|
21
20
|
@scopes = [(outer_scope || {})]
|
22
21
|
@registers = registers
|
23
22
|
@errors = []
|
24
|
-
@
|
25
|
-
@resource_limits
|
26
|
-
@resource_limits[:assign_score_current] = 0
|
27
|
-
@parsed_expression = Hash.new{ |cache, markup| cache[markup] = Expression.parse(markup) }
|
23
|
+
@partial = false
|
24
|
+
@resource_limits = resource_limits || ResourceLimits.new(Template.default_resource_limits)
|
28
25
|
squash_instance_assigns_with_environments
|
29
26
|
|
30
27
|
@this_stack_used = false
|
31
28
|
|
32
29
|
if rethrow_errors
|
33
|
-
self.exception_handler = ->(e) {
|
30
|
+
self.exception_handler = ->(e) { raise }
|
34
31
|
end
|
35
32
|
|
36
33
|
@interrupts = []
|
37
34
|
@filters = []
|
35
|
+
@global_filter = nil
|
38
36
|
end
|
39
37
|
|
40
|
-
def
|
41
|
-
@
|
42
|
-
obj.length
|
43
|
-
else
|
44
|
-
1
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def resource_limits_reached?
|
49
|
-
(@resource_limits[:render_length_limit] && @resource_limits[:render_length_current] > @resource_limits[:render_length_limit]) ||
|
50
|
-
(@resource_limits[:render_score_limit] && @resource_limits[:render_score_current] > @resource_limits[:render_score_limit] ) ||
|
51
|
-
(@resource_limits[:assign_score_limit] && @resource_limits[:assign_score_current] > @resource_limits[:assign_score_limit] )
|
38
|
+
def warnings
|
39
|
+
@warnings ||= []
|
52
40
|
end
|
53
41
|
|
54
42
|
def strainer
|
@@ -65,8 +53,12 @@ module Liquid
|
|
65
53
|
@strainer = nil
|
66
54
|
end
|
67
55
|
|
56
|
+
def apply_global_filter(obj)
|
57
|
+
global_filter.nil? ? obj : global_filter.call(obj)
|
58
|
+
end
|
59
|
+
|
68
60
|
# are there any not handled interrupts?
|
69
|
-
def
|
61
|
+
def interrupt?
|
70
62
|
!@interrupts.empty?
|
71
63
|
end
|
72
64
|
|
@@ -80,15 +72,31 @@ module Liquid
|
|
80
72
|
@interrupts.pop
|
81
73
|
end
|
82
74
|
|
83
|
-
|
84
|
-
def handle_error(e, token=nil)
|
75
|
+
def handle_error(e, line_number = nil)
|
85
76
|
if e.is_a?(Liquid::Error)
|
86
|
-
e.
|
77
|
+
e.template_name ||= template_name
|
78
|
+
e.line_number ||= line_number
|
87
79
|
end
|
88
80
|
|
81
|
+
output = nil
|
82
|
+
|
83
|
+
if exception_handler
|
84
|
+
result = exception_handler.call(e)
|
85
|
+
case result
|
86
|
+
when Exception
|
87
|
+
e = result
|
88
|
+
if e.is_a?(Liquid::Error)
|
89
|
+
e.template_name ||= template_name
|
90
|
+
e.line_number ||= line_number
|
91
|
+
end
|
92
|
+
when String
|
93
|
+
output = result
|
94
|
+
else
|
95
|
+
raise if result
|
96
|
+
end
|
97
|
+
end
|
89
98
|
errors.push(e)
|
90
|
-
|
91
|
-
Liquid::Error.render(e)
|
99
|
+
output || Liquid::Error.render(e)
|
92
100
|
end
|
93
101
|
|
94
102
|
def invoke(method, *args)
|
@@ -96,7 +104,7 @@ module Liquid
|
|
96
104
|
end
|
97
105
|
|
98
106
|
# Push new local scope on the stack. use <tt>Context#stack</tt> instead
|
99
|
-
def push(new_scope={})
|
107
|
+
def push(new_scope = {})
|
100
108
|
@scopes.unshift(new_scope)
|
101
109
|
raise StackLevelError, "Nesting too deep".freeze if @scopes.length > 100
|
102
110
|
end
|
@@ -120,7 +128,7 @@ module Liquid
|
|
120
128
|
# end
|
121
129
|
#
|
122
130
|
# context['var] #=> nil
|
123
|
-
def stack(new_scope=nil)
|
131
|
+
def stack(new_scope = nil)
|
124
132
|
old_stack_used = @this_stack_used
|
125
133
|
if new_scope
|
126
134
|
push(new_scope)
|
@@ -157,10 +165,10 @@ module Liquid
|
|
157
165
|
# Example:
|
158
166
|
# products == empty #=> products.empty?
|
159
167
|
def [](expression)
|
160
|
-
evaluate(
|
168
|
+
evaluate(Expression.parse(expression))
|
161
169
|
end
|
162
170
|
|
163
|
-
def
|
171
|
+
def key?(key)
|
164
172
|
self[key] != nil
|
165
173
|
end
|
166
174
|
|
@@ -170,10 +178,9 @@ module Liquid
|
|
170
178
|
|
171
179
|
# Fetches an object starting at the local scope and then moving up the hierachy
|
172
180
|
def find_variable(key)
|
173
|
-
|
174
181
|
# This was changed from find() to find_index() because this is a very hot
|
175
182
|
# path and find_index() is optimized in MRI to reduce object allocation
|
176
|
-
index = @scopes.find_index { |s| s.
|
183
|
+
index = @scopes.find_index { |s| s.key?(key) }
|
177
184
|
scope = @scopes[index] if index
|
178
185
|
|
179
186
|
variable = nil
|
@@ -188,13 +195,13 @@ module Liquid
|
|
188
195
|
end
|
189
196
|
end
|
190
197
|
|
191
|
-
scope
|
192
|
-
variable
|
198
|
+
scope ||= @environments.last || @scopes.last
|
199
|
+
variable ||= lookup_and_evaluate(scope, key)
|
193
200
|
|
194
201
|
variable = variable.to_liquid
|
195
202
|
variable.context = self if variable.respond_to?(:context=)
|
196
203
|
|
197
|
-
|
204
|
+
variable
|
198
205
|
end
|
199
206
|
|
200
207
|
def lookup_and_evaluate(obj, key)
|
@@ -206,15 +213,16 @@ module Liquid
|
|
206
213
|
end
|
207
214
|
|
208
215
|
private
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
+
|
217
|
+
def squash_instance_assigns_with_environments
|
218
|
+
@scopes.last.each_key do |k|
|
219
|
+
@environments.each do |env|
|
220
|
+
if env.key?(k)
|
221
|
+
scopes.last[k] = lookup_and_evaluate(env, k)
|
222
|
+
break
|
216
223
|
end
|
217
224
|
end
|
218
|
-
end
|
225
|
+
end
|
226
|
+
end # squash_instance_assigns_with_environments
|
219
227
|
end # Context
|
220
228
|
end # Liquid
|
data/lib/liquid/document.rb
CHANGED
@@ -1,17 +1,27 @@
|
|
1
1
|
module Liquid
|
2
|
-
class Document <
|
3
|
-
def self.parse(tokens,
|
4
|
-
|
5
|
-
|
2
|
+
class Document < BlockBody
|
3
|
+
def self.parse(tokens, parse_context)
|
4
|
+
doc = new
|
5
|
+
doc.parse(tokens, parse_context)
|
6
|
+
doc
|
6
7
|
end
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
def parse(tokens, parse_context)
|
10
|
+
super do |end_tag_name, end_tag_params|
|
11
|
+
unknown_tag(end_tag_name, parse_context) if end_tag_name
|
12
|
+
end
|
13
|
+
rescue SyntaxError => e
|
14
|
+
e.line_number ||= parse_context.line_number
|
15
|
+
raise
|
11
16
|
end
|
12
17
|
|
13
|
-
|
14
|
-
|
18
|
+
def unknown_tag(tag, parse_context)
|
19
|
+
case tag
|
20
|
+
when 'else'.freeze, 'end'.freeze
|
21
|
+
raise SyntaxError.new(parse_context.locale.t("errors.syntax.unexpected_outer_tag".freeze, tag: tag))
|
22
|
+
else
|
23
|
+
raise SyntaxError.new(parse_context.locale.t("errors.syntax.unknown_tag".freeze, tag: tag))
|
24
|
+
end
|
15
25
|
end
|
16
26
|
end
|
17
27
|
end
|
data/lib/liquid/drop.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'set'
|
2
2
|
|
3
3
|
module Liquid
|
4
|
-
|
5
4
|
# A drop in liquid is a class which allows you to export DOM like things to liquid.
|
6
5
|
# Methods of drops are callable.
|
7
6
|
# The main use for liquid drops is to implement lazy loaded objects.
|
@@ -19,28 +18,26 @@ module Liquid
|
|
19
18
|
# tmpl = Liquid::Template.parse( ' {% for product in product.top_sales %} {{ product.name }} {%endfor%} ' )
|
20
19
|
# tmpl.render('product' => ProductDrop.new ) # will invoke top_sales query.
|
21
20
|
#
|
22
|
-
# Your drop can either implement the methods sans any parameters
|
23
|
-
# catch all.
|
21
|
+
# Your drop can either implement the methods sans any parameters
|
22
|
+
# or implement the liquid_method_missing(name) method which is a catch all.
|
24
23
|
class Drop
|
25
24
|
attr_writer :context
|
26
25
|
|
27
|
-
EMPTY_STRING = ''.freeze
|
28
|
-
|
29
26
|
# Catch all for the method
|
30
|
-
def
|
27
|
+
def liquid_method_missing(_method)
|
31
28
|
nil
|
32
29
|
end
|
33
30
|
|
34
31
|
# called by liquid to invoke a drop
|
35
32
|
def invoke_drop(method_or_key)
|
36
|
-
if
|
33
|
+
if self.class.invokable?(method_or_key)
|
37
34
|
send(method_or_key)
|
38
35
|
else
|
39
|
-
|
36
|
+
liquid_method_missing(method_or_key)
|
40
37
|
end
|
41
38
|
end
|
42
39
|
|
43
|
-
def
|
40
|
+
def key?(_name)
|
44
41
|
true
|
45
42
|
end
|
46
43
|
|
@@ -56,12 +53,14 @@ module Liquid
|
|
56
53
|
self.class.name
|
57
54
|
end
|
58
55
|
|
59
|
-
|
60
|
-
|
61
|
-
private
|
56
|
+
alias_method :[], :invoke_drop
|
62
57
|
|
63
58
|
# Check for method existence without invoking respond_to?, which creates symbols
|
64
59
|
def self.invokable?(method_name)
|
60
|
+
invokable_methods.include?(method_name.to_s)
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.invokable_methods
|
65
64
|
unless @invokable_methods
|
66
65
|
blacklist = Liquid::Drop.public_instance_methods + [:each]
|
67
66
|
if include?(Enumerable)
|
@@ -71,7 +70,7 @@ module Liquid
|
|
71
70
|
whitelist = [:to_liquid] + (public_instance_methods - blacklist)
|
72
71
|
@invokable_methods = Set.new(whitelist.map(&:to_s))
|
73
72
|
end
|
74
|
-
@invokable_methods
|
73
|
+
@invokable_methods
|
75
74
|
end
|
76
75
|
end
|
77
76
|
end
|
data/lib/liquid/errors.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
module Liquid
|
2
2
|
class Error < ::StandardError
|
3
3
|
attr_accessor :line_number
|
4
|
+
attr_accessor :template_name
|
4
5
|
attr_accessor :markup_context
|
5
6
|
|
6
|
-
def to_s(with_prefix=true)
|
7
|
+
def to_s(with_prefix = true)
|
7
8
|
str = ""
|
8
9
|
str << message_prefix if with_prefix
|
9
10
|
str << super()
|
@@ -16,17 +17,11 @@ module Liquid
|
|
16
17
|
str
|
17
18
|
end
|
18
19
|
|
19
|
-
def set_line_number_from_token(token)
|
20
|
-
return unless token.respond_to?(:line_number)
|
21
|
-
return if self.line_number
|
22
|
-
self.line_number = token.line_number
|
23
|
-
end
|
24
|
-
|
25
20
|
def self.render(e)
|
26
21
|
if e.is_a?(Liquid::Error)
|
27
22
|
e.to_s
|
28
23
|
else
|
29
|
-
"Liquid error: #{e
|
24
|
+
"Liquid error: #{e}"
|
30
25
|
end
|
31
26
|
end
|
32
27
|
|
@@ -41,7 +36,9 @@ module Liquid
|
|
41
36
|
end
|
42
37
|
|
43
38
|
if line_number
|
44
|
-
str << " (
|
39
|
+
str << " ("
|
40
|
+
str << template_name << " " if template_name
|
41
|
+
str << "line " << line_number.to_s << ")"
|
45
42
|
end
|
46
43
|
|
47
44
|
str << ": "
|
@@ -49,12 +46,14 @@ module Liquid
|
|
49
46
|
end
|
50
47
|
end
|
51
48
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
49
|
+
ArgumentError = Class.new(Error)
|
50
|
+
ContextError = Class.new(Error)
|
51
|
+
FileSystemError = Class.new(Error)
|
52
|
+
StandardError = Class.new(Error)
|
53
|
+
SyntaxError = Class.new(Error)
|
54
|
+
StackLevelError = Class.new(Error)
|
55
|
+
TaintedError = Class.new(Error)
|
56
|
+
MemoryError = Class.new(Error)
|
57
|
+
ZeroDivisionError = Class.new(Error)
|
58
|
+
FloatDomainError = Class.new(Error)
|
60
59
|
end
|