myrrha 1.0.0
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.
- data/CHANGELOG.md +5 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +41 -0
- data/LICENCE.md +22 -0
- data/Manifest.txt +13 -0
- data/README.md +337 -0
- data/Rakefile +23 -0
- data/examples/String#toXXX.rb +40 -0
- data/examples/coerce.rb +26 -0
- data/examples/coerce_foo.rb +12 -0
- data/examples/coerce_foo2.rb +17 -0
- data/examples/coerce_foo3.rb +23 -0
- data/examples/coerce_intro.rb +10 -0
- data/examples/coerce_noext.rb +6 -0
- data/examples/examples_helper.rb +17 -0
- data/examples/friendly_but_safe_api.rb +73 -0
- data/examples/to_ruby_literal.rb +16 -0
- data/examples/to_ruby_literal_foo.rb +14 -0
- data/examples/to_ruby_literal_foo2.rb +17 -0
- data/examples/to_ruby_literal_foo3.rb +21 -0
- data/examples/to_ruby_literal_noext.rb +5 -0
- data/lib/myrrha/coerce.rb +93 -0
- data/lib/myrrha/loader.rb +0 -0
- data/lib/myrrha/to_ruby_literal.rb +76 -0
- data/lib/myrrha/version.rb +14 -0
- data/lib/myrrha/with_core_ext.rb +2 -0
- data/lib/myrrha.rb +295 -0
- data/myrrha.gemspec +191 -0
- data/myrrha.noespec +37 -0
- data/spec/coercions/test_append.rb +11 -0
- data/spec/coercions/test_belongs_to.rb +29 -0
- data/spec/coercions/test_convert.rb +23 -0
- data/spec/coercions/test_dup.rb +21 -0
- data/spec/coercions/test_subdomain.rb +11 -0
- data/spec/shared/a_value.rb +33 -0
- data/spec/spec_helper.rb +34 -0
- data/spec/test_assumptions.rb +18 -0
- data/spec/test_coerce.rb +119 -0
- data/spec/test_myrrha.rb +87 -0
- data/spec/test_to_ruby_literal.rb +19 -0
- data/spec/test_value.rb +6 -0
- data/tasks/debug_mail.rake +78 -0
- data/tasks/debug_mail.txt +13 -0
- data/tasks/examples.rake +13 -0
- data/tasks/gem.rake +68 -0
- data/tasks/spec_test.rake +79 -0
- data/tasks/unit_test.rake +77 -0
- data/tasks/yard.rake +51 -0
- metadata +195 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'myrrha/with_core_ext'
|
3
|
+
require 'myrrha/to_ruby_literal'
|
4
|
+
|
5
|
+
require 'date'
|
6
|
+
require 'myrrha/with_core_ext'
|
7
|
+
require 'myrrha/to_ruby_literal'
|
8
|
+
|
9
|
+
1.to_ruby_literal # => "1"
|
10
|
+
Date.today.to_ruby_literal # => "Marshal.load('...')"
|
11
|
+
["hello", Date.today].to_ruby_literal # => "['hello', Marshal.load('...')]"
|
12
|
+
|
13
|
+
(1..10).to_ruby_literal # => "1..10"
|
14
|
+
|
15
|
+
today = Date.today
|
16
|
+
(today..today+1).to_ruby_literal # => "Marshal.load('...')"
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "myrrha/to_ruby_literal"
|
2
|
+
|
3
|
+
class Foo
|
4
|
+
attr_reader :arg
|
5
|
+
def initialize(arg)
|
6
|
+
@arg = arg
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
Myrrha::ToRubyLiteral.append do |r|
|
11
|
+
r.coercion(Foo) do |foo, _|
|
12
|
+
"Foo.new(#{foo.arg.inspect})"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
Myrrha.to_ruby_literal(Foo.new(:hello))
|
17
|
+
# => "Foo.new(:hello)"
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "myrrha/to_ruby_literal"
|
2
|
+
|
3
|
+
class Foo
|
4
|
+
attr_reader :arg
|
5
|
+
def initialize(arg)
|
6
|
+
@arg = arg
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
MyRules = Myrrha::ToRubyLiteral.dup.append do |r|
|
11
|
+
r.coercion(Foo) do |foo, _|
|
12
|
+
"Foo.new(#{foo.arg.inspect})"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Myrrha.to_ruby_literal is actually a shortcut for:
|
17
|
+
Myrrha::ToRubyLiteral.apply(Foo.new(:hello))
|
18
|
+
# => "Marshal.load('...')"
|
19
|
+
|
20
|
+
MyRules.apply(Foo.new(:hello))
|
21
|
+
# => "Foo.new(:hello)"
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'myrrha'
|
2
|
+
module Myrrha
|
3
|
+
|
4
|
+
#
|
5
|
+
# Defines the missing Boolean type.
|
6
|
+
#
|
7
|
+
# This module mimics a Ruby missing Boolean type.
|
8
|
+
#
|
9
|
+
module Boolean
|
10
|
+
|
11
|
+
#
|
12
|
+
# Returns Object, as the superclass of Boolean
|
13
|
+
#
|
14
|
+
# @return [Class] Object
|
15
|
+
#
|
16
|
+
def self.superclass; Object; end
|
17
|
+
|
18
|
+
#
|
19
|
+
# Returns true if `val` is <code>true</code> or <code>false</code>, false
|
20
|
+
# otherwise.
|
21
|
+
#
|
22
|
+
def self.===(val)
|
23
|
+
(val == true) || (val == false)
|
24
|
+
end
|
25
|
+
|
26
|
+
end # module Boolean
|
27
|
+
|
28
|
+
#
|
29
|
+
# Coerces _s_ to a Boolean
|
30
|
+
#
|
31
|
+
# This method mimics Ruby's Integer(), Float(), etc. for Boolean values.
|
32
|
+
#
|
33
|
+
# @param [Object] s a Boolean or a String
|
34
|
+
# @return [Boolean] true if `s` is already true of the string 'true',
|
35
|
+
# false if `s` is already false of the string 'false'.
|
36
|
+
# @raise [ArgumentError] if `s` cannot be coerced to a boolean.
|
37
|
+
#
|
38
|
+
def self.Boolean(s)
|
39
|
+
if (s==true || s.to_str.strip == "true")
|
40
|
+
true
|
41
|
+
elsif (s==false || s.to_str.strip == "false")
|
42
|
+
false
|
43
|
+
else
|
44
|
+
raise ArgumentError, "invalid value for Boolean: \"#{s}\""
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Defines basic coercions for Ruby, mostly from String
|
49
|
+
Coerce = coercions do |g|
|
50
|
+
|
51
|
+
# NilClass should return immediately
|
52
|
+
g.upon(NilClass) do |s,t|
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
|
56
|
+
# Use t.coerce if it exists
|
57
|
+
g.upon(lambda{|s,t| t.respond_to?(:coerce)}) do |s,t|
|
58
|
+
t.coerce(s)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Specific basic rules
|
62
|
+
g.coercion String, Integer, lambda{|s,t| Integer(s) }
|
63
|
+
g.coercion String, Float, lambda{|s,t| Float(s) }
|
64
|
+
g.coercion String, Boolean, lambda{|s,t| Boolean(s) }
|
65
|
+
g.coercion Integer, Float, lambda{|s,t| Float(s) }
|
66
|
+
g.coercion String, Symbol, lambda{|s,t| s.to_sym }
|
67
|
+
g.coercion String, Regexp, lambda{|s,t| Regexp.compile(s) }
|
68
|
+
|
69
|
+
# By default, we try to invoke :parse on the class
|
70
|
+
g.fallback(String) do |s,t|
|
71
|
+
t.respond_to?(:parse) ? t.parse(s.to_str) : throw(:nextrule)
|
72
|
+
end
|
73
|
+
|
74
|
+
end # Coerce
|
75
|
+
|
76
|
+
def self.coerce(value, domain)
|
77
|
+
Coerce.apply(value, domain)
|
78
|
+
end
|
79
|
+
|
80
|
+
end # module Myrrha
|
81
|
+
|
82
|
+
if Myrrha.core_ext?
|
83
|
+
Boolean = Myrrha::Boolean
|
84
|
+
def Boolean(s)
|
85
|
+
Myrrha::Boolean(s)
|
86
|
+
end
|
87
|
+
class Object
|
88
|
+
private
|
89
|
+
def coerce(value, domain)
|
90
|
+
Myrrha.coerce(value, domain)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
File without changes
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'myrrha'
|
2
|
+
module Myrrha
|
3
|
+
|
4
|
+
# These are all classes for which using inspect is safe for to_ruby_literal
|
5
|
+
TO_RUBY_THROUGH_INSPECT = [ NilClass, TrueClass, FalseClass,
|
6
|
+
Fixnum, Bignum, Float,
|
7
|
+
String, Symbol, Class, Module, Regexp ]
|
8
|
+
|
9
|
+
# Defines basic coercions for implementing to_ruby_literal
|
10
|
+
ToRubyLiteral = coercions do |r|
|
11
|
+
r.main_target_domain = :to_ruby_literal
|
12
|
+
|
13
|
+
r.upon(Object) do |s,t|
|
14
|
+
s.to_ruby_literal{ throw :nextrule }
|
15
|
+
end
|
16
|
+
|
17
|
+
# On safe .inspect
|
18
|
+
safe = lambda{|x| TO_RUBY_THROUGH_INSPECT.include?(x.class)}
|
19
|
+
r.coercion(safe) do |s,t|
|
20
|
+
s.inspect
|
21
|
+
end
|
22
|
+
|
23
|
+
# Best-effort on Range or let it be marshalled
|
24
|
+
r.coercion(Range) do |s,t|
|
25
|
+
(TO_RUBY_THROUGH_INSPECT.include?(s.first.class) &&
|
26
|
+
TO_RUBY_THROUGH_INSPECT.include?(s.last.class)) ?
|
27
|
+
s.inspect : throw(:nextrule)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Be friendly on array
|
31
|
+
r.coercion(Array) do |s,t|
|
32
|
+
"[" + s.collect{|v| r.apply(v)}.join(', ') + "]"
|
33
|
+
end
|
34
|
+
|
35
|
+
# As well as on Hash
|
36
|
+
r.coercion(Hash) do |s,t|
|
37
|
+
"{" + s.collect{|k,v|
|
38
|
+
r.apply(k) + " => " + r.apply(v)
|
39
|
+
}.join(', ') + "}"
|
40
|
+
end
|
41
|
+
|
42
|
+
# Use Marshal by default
|
43
|
+
r.fallback(Object) do |s,t|
|
44
|
+
"Marshal.load(#{Marshal.dump(s).inspect})"
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# Converts `value` to a ruby literal
|
51
|
+
#
|
52
|
+
# @param [Object] value any ruby value
|
53
|
+
# @return [String] a representation `s` of `value` such that
|
54
|
+
# <code>Kernel.eval(s) == value</code> is true
|
55
|
+
#
|
56
|
+
def self.to_ruby_literal(value = self)
|
57
|
+
block_given? ?
|
58
|
+
yield :
|
59
|
+
ToRubyLiteral.apply(value)
|
60
|
+
end
|
61
|
+
|
62
|
+
end # module Myrrha
|
63
|
+
|
64
|
+
class Object
|
65
|
+
|
66
|
+
#
|
67
|
+
# Converts self to a ruby literal
|
68
|
+
#
|
69
|
+
# @return [String] a representation `s` of self such that
|
70
|
+
# <code>Kernel.eval(s) == value</code> is true
|
71
|
+
#
|
72
|
+
def to_ruby_literal
|
73
|
+
block_given? ? yield : Myrrha.to_ruby_literal(self)
|
74
|
+
end
|
75
|
+
|
76
|
+
end if Myrrha.core_ext?
|
data/lib/myrrha.rb
ADDED
@@ -0,0 +1,295 @@
|
|
1
|
+
#
|
2
|
+
# Myrrha -- the missing coercion framework for Ruby
|
3
|
+
#
|
4
|
+
module Myrrha
|
5
|
+
|
6
|
+
#
|
7
|
+
# Raised when a coercion fails
|
8
|
+
#
|
9
|
+
class Error < StandardError; end
|
10
|
+
|
11
|
+
#
|
12
|
+
# Builds a set of coercions rules.
|
13
|
+
#
|
14
|
+
# Example:
|
15
|
+
#
|
16
|
+
# rules = Myrrha.coercions do |c|
|
17
|
+
# c.coercion String, Integer, lambda{|s,t| Integer(s)}
|
18
|
+
# #
|
19
|
+
# # [...]
|
20
|
+
# #
|
21
|
+
# c.fallback String, lambda{|s,t| ... }
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
def self.coercions(&block)
|
25
|
+
Coercions.new(&block)
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# Defines a set of coercion rules
|
30
|
+
#
|
31
|
+
class Coercions
|
32
|
+
|
33
|
+
# @return [Domain] The main target domain, if any
|
34
|
+
attr_accessor :main_target_domain
|
35
|
+
|
36
|
+
#
|
37
|
+
# Creates an empty list of coercion rules
|
38
|
+
#
|
39
|
+
def initialize(upons = [], rules = [], fallbacks = [])
|
40
|
+
@upons = upons
|
41
|
+
@rules = rules
|
42
|
+
@fallbacks = fallbacks
|
43
|
+
@appender = :<<
|
44
|
+
yield(self) if block_given?
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
# Appends the list of rules with new ones.
|
49
|
+
#
|
50
|
+
# New upon, coercion and fallback rules will be put after the already
|
51
|
+
# existing ones, in each case.
|
52
|
+
#
|
53
|
+
# Example:
|
54
|
+
#
|
55
|
+
# rules = Myrrha.coercions do ... end
|
56
|
+
# rules.append do |r|
|
57
|
+
#
|
58
|
+
# # [previous coercion rules would come here]
|
59
|
+
#
|
60
|
+
# # install new rules
|
61
|
+
# r.coercion String, Float, lambda{|v,t| Float(t)}
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
def append(&proc)
|
65
|
+
extend_rules(:<<, proc)
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# Prepends the list of rules with new ones.
|
70
|
+
#
|
71
|
+
# New upon, coercion and fallback rules will be put before the already
|
72
|
+
# existing ones, in each case.
|
73
|
+
#
|
74
|
+
# Example:
|
75
|
+
#
|
76
|
+
# rules = Myrrha.coercions do ... end
|
77
|
+
# rules.prepend do |r|
|
78
|
+
#
|
79
|
+
# # install new rules
|
80
|
+
# r.coercion String, Float, lambda{|v,t| Float(t)}
|
81
|
+
#
|
82
|
+
# # [previous coercion rules would come here]
|
83
|
+
#
|
84
|
+
# end
|
85
|
+
#
|
86
|
+
def prepend(&proc)
|
87
|
+
extend_rules(:unshift, proc)
|
88
|
+
end
|
89
|
+
|
90
|
+
#
|
91
|
+
# Adds an upon rule for a source domain.
|
92
|
+
#
|
93
|
+
# Example:
|
94
|
+
#
|
95
|
+
# Myrrha.coercions do |r|
|
96
|
+
#
|
97
|
+
# # Don't even try something else on nil
|
98
|
+
# r.upon(NilClass){|s,t| nil}
|
99
|
+
# [...]
|
100
|
+
#
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
# @param source [Domain] a source domain (mimic Domain)
|
104
|
+
# @param converter [Converter] an optional converter (mimic Converter)
|
105
|
+
# @param convproc [Proc] used when converter is not specified
|
106
|
+
# @return self
|
107
|
+
#
|
108
|
+
def upon(source, converter = nil, &convproc)
|
109
|
+
@upons.send(@appender, [source, nil, converter || convproc])
|
110
|
+
self
|
111
|
+
end
|
112
|
+
|
113
|
+
#
|
114
|
+
# Adds a coercion rule from a source to a target domain.
|
115
|
+
#
|
116
|
+
# The conversion can be provided through `converter` or via a block
|
117
|
+
# directly. See main documentation about recognized converters.
|
118
|
+
#
|
119
|
+
# Example:
|
120
|
+
#
|
121
|
+
# Myrrha.coercions do |r|
|
122
|
+
#
|
123
|
+
# # With an explicit proc
|
124
|
+
# r.coercion String, Integer, lambda{|v,t|
|
125
|
+
# Integer(v)
|
126
|
+
# }
|
127
|
+
#
|
128
|
+
# # With an implicit proc
|
129
|
+
# r.coercion(String, Float) do |v,t|
|
130
|
+
# Float(v)
|
131
|
+
# end
|
132
|
+
#
|
133
|
+
# end
|
134
|
+
#
|
135
|
+
# @param source [Domain] a source domain (mimicing Domain)
|
136
|
+
# @param target [Domain] a target domain (mimicing Domain)
|
137
|
+
# @param converter [Converter] an optional converter (mimic Converter)
|
138
|
+
# @param convproc [Proc] used when converter is not specified
|
139
|
+
# @return self
|
140
|
+
#
|
141
|
+
def coercion(source, target = main_target_domain, converter = nil, &convproc)
|
142
|
+
@rules.send(@appender, [source, target, converter || convproc])
|
143
|
+
self
|
144
|
+
end
|
145
|
+
|
146
|
+
#
|
147
|
+
# Adds a fallback rule for a source domain.
|
148
|
+
#
|
149
|
+
# Example:
|
150
|
+
#
|
151
|
+
# Myrrha.coercions do |r|
|
152
|
+
#
|
153
|
+
# # Add a 'last chance' rule for Strings
|
154
|
+
# r.fallback(String) do |v,t|
|
155
|
+
# # the user wants _v_ to be converted to a value of domain _t_
|
156
|
+
# end
|
157
|
+
#
|
158
|
+
# end
|
159
|
+
#
|
160
|
+
# @param source [Domain] a source domain (mimic Domain)
|
161
|
+
# @param converter [Converter] an optional converter (mimic Converter)
|
162
|
+
# @param convproc [Proc] used when converter is not specified
|
163
|
+
# @return self
|
164
|
+
#
|
165
|
+
def fallback(source, converter = nil, &convproc)
|
166
|
+
@fallbacks.send(@appender, [source, nil, converter || convproc])
|
167
|
+
self
|
168
|
+
end
|
169
|
+
|
170
|
+
#
|
171
|
+
# Coerces `value` to an element of `target_domain`
|
172
|
+
#
|
173
|
+
# This method tries each coercion rule, then each fallback in turn. Rules
|
174
|
+
# for which source and target domain match are executed until one succeeds.
|
175
|
+
# A Myrrha::Error is raised if no rule matches or executes successfuly.
|
176
|
+
#
|
177
|
+
# @param [Object] value any ruby value
|
178
|
+
# @param [Domain] target_domain a target domain to convert to (mimic Domain)
|
179
|
+
# @return self
|
180
|
+
#
|
181
|
+
def coerce(value, target_domain = main_target_domain)
|
182
|
+
return value if belongs_to?(value, target_domain)
|
183
|
+
error = nil
|
184
|
+
each_rule do |from,to,converter|
|
185
|
+
next unless from.nil? or belongs_to?(value, from, target_domain)
|
186
|
+
next unless to.nil? or subdomain?(to, target_domain)
|
187
|
+
begin
|
188
|
+
catch(:nextrule){
|
189
|
+
return convert(value, target_domain, converter)
|
190
|
+
}
|
191
|
+
rescue => ex
|
192
|
+
error = ex.message unless error
|
193
|
+
end
|
194
|
+
end
|
195
|
+
msg = "Unable to coerce `#{value}` to #{target_domain}"
|
196
|
+
msg += " (#{error})" if error
|
197
|
+
raise Error, msg
|
198
|
+
end
|
199
|
+
alias :apply :coerce
|
200
|
+
|
201
|
+
#
|
202
|
+
# Returns true if `value` can be considered as a valid element of the
|
203
|
+
# domain `domain`, false otherwise.
|
204
|
+
#
|
205
|
+
# @param [Object] value any ruby value
|
206
|
+
# @param [Domain] domain a domain (mimic Domain)
|
207
|
+
# @return [Boolean] true if `value` belongs to `domain`, false otherwise
|
208
|
+
#
|
209
|
+
def belongs_to?(value, domain, target_domain = domain)
|
210
|
+
case domain
|
211
|
+
when Proc
|
212
|
+
if domain.arity == 2
|
213
|
+
domain.call(value, target_domain)
|
214
|
+
elsif RUBY_VERSION < "1.9"
|
215
|
+
domain.call(value)
|
216
|
+
elsif domain
|
217
|
+
domain === value
|
218
|
+
end
|
219
|
+
else
|
220
|
+
domain.respond_to?(:===) ?
|
221
|
+
domain === value :
|
222
|
+
false
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
#
|
227
|
+
# Returns `true` if `child` can be considered a valid sub domain of
|
228
|
+
# `parent`, false otherwise.
|
229
|
+
#
|
230
|
+
# @param [Domain] child a domain (mimic Domain)
|
231
|
+
# @param [Domain] parent another domain (mimic Domain)
|
232
|
+
# @return [Boolean] true if `child` is a subdomain of `parent`, false
|
233
|
+
# otherwise.
|
234
|
+
#
|
235
|
+
def subdomain?(child, parent)
|
236
|
+
return true if child == parent
|
237
|
+
(child.respond_to?(:superclass) && child.superclass) ?
|
238
|
+
subdomain?(child.superclass, parent) :
|
239
|
+
false
|
240
|
+
end
|
241
|
+
|
242
|
+
#
|
243
|
+
# Duplicates this set of rules in such a way that the original will not
|
244
|
+
# be affected by any change made to the copy.
|
245
|
+
#
|
246
|
+
# @return [Coercions] a copy of this set of rules
|
247
|
+
#
|
248
|
+
def dup
|
249
|
+
Coercions.new(@upons.dup, @rules.dup, @fallbacks.dup)
|
250
|
+
end
|
251
|
+
|
252
|
+
private
|
253
|
+
|
254
|
+
# Extends existing rules
|
255
|
+
def extend_rules(appender, block)
|
256
|
+
@appender = appender
|
257
|
+
block.call(self)
|
258
|
+
self
|
259
|
+
end
|
260
|
+
|
261
|
+
#
|
262
|
+
# Yields each rule in turn (upons, coercions then fallbacks)
|
263
|
+
#
|
264
|
+
def each_rule(&proc)
|
265
|
+
@upons.each(&proc)
|
266
|
+
@rules.each(&proc)
|
267
|
+
@fallbacks.each(&proc)
|
268
|
+
end
|
269
|
+
|
270
|
+
#
|
271
|
+
# Calls converter on a (value,target_domain) pair.
|
272
|
+
#
|
273
|
+
def convert(value, target_domain, converter)
|
274
|
+
if converter.respond_to?(:call)
|
275
|
+
converter.call(value, target_domain)
|
276
|
+
else
|
277
|
+
raise ArgumentError, "Unable to use #{converter} for coercing"
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
end # class Coercions
|
282
|
+
|
283
|
+
# Myrrha main options
|
284
|
+
OPTIONS = {
|
285
|
+
:core_ext => false
|
286
|
+
}
|
287
|
+
|
288
|
+
# Install core extensions?
|
289
|
+
def self.core_ext?
|
290
|
+
OPTIONS[:core_ext]
|
291
|
+
end
|
292
|
+
|
293
|
+
end # module Myrrha
|
294
|
+
require "myrrha/version"
|
295
|
+
require "myrrha/loader"
|