myrrha 1.2.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,8 +1,41 @@
1
+ # 2.0.0 / 2012-09-26
2
+
3
+ * Removed support for ruby 1.8.7
4
+ * Coercions#subdomain? and Coercions#belongs_to? are now protected
5
+ * In case of coercion failure, Myrrha::Error keeps the first coercion error under `cause`
6
+ (that might be nil if no rule was triggered or no rule explcitely failed).
7
+ * Added Coercions#delegate as a shortcut for upon rules that work by delegation to the
8
+ value.
9
+
10
+ * Defining domains through subclassing and specialization by constraints must now be made
11
+ as shown below. Factored domains gain a Coercions instance under `coercions`.
12
+
13
+ class NegInt < Integer
14
+ extend Myrrha::Domain::SByC.new(Integer, [], lambda{|i| i<0})
15
+
16
+ coercions do |c|
17
+ c.coercion(String){|v,t| ...}
18
+ end
19
+ end
20
+
21
+ * Added a Domain::Impl module for implementing domains from scratch (vs. sbyc). Factored
22
+ domains have a default constructor taking components as parameters, an attribute reader
23
+ for each component as well as hash and equality methods properly defined. They also have
24
+ a Coercions instance under `coercions`.
25
+
26
+ class Point
27
+ include Domain::Impl.new(:x, :y)
28
+
29
+ coercions do |c|
30
+ c.coercion(String){|v,t| ...}
31
+ end
32
+ end
33
+
1
34
  # 1.2.2 / 2012-01-26
2
35
 
3
36
  * Ensure that inheritance intuitively applies when duplicating a set of coercion
4
- rules. Rules that, in the parent, rely on the recursive application of other
5
- rules (such as recursively applying coercions on arrays) will now correctly
37
+ rules. Rules that, in the parent, rely on the recursive application of other
38
+ rules (such as recursively applying coercions on arrays) will now correctly
6
39
  use the rules defined on the duplicated Coercions object.
7
40
 
8
41
  In particular, this means that the following scenario now correctly works:
@@ -12,7 +45,7 @@
12
45
  end
13
46
  Dupped.apply([1, Foo.new])
14
47
 
15
- In the scenario above, Foo was marshalled as the new rules was not used by
48
+ In the scenario above, Foo was marshalled as the new rules was not used by
16
49
  the Array rule, defined on the parent.
17
50
 
18
51
  # 1.2.1 / 2011-08-31
@@ -25,16 +58,16 @@
25
58
  * Added the ability to created SByC domains through simple module extension:
26
59
 
27
60
  NegInt = Myrrha.domain(Integer){|i| i < 0}
28
-
61
+
29
62
  can also be built the following way:
30
63
 
31
64
  class NegInt < Integer
32
65
  extend Myrrha::Domain
33
-
66
+
34
67
  def self.predicate
35
68
  @predicate ||= lambda{|i| i < 0}
36
69
  end
37
-
70
+
38
71
  end
39
72
 
40
73
  * Cleaned the development dependencies, travis-ci.org continuous integration,
@@ -53,57 +86,57 @@
53
86
 
54
87
  * Added following coercion rules for Booleans
55
88
 
56
- coerce("true", TrueClass) # => true
57
- coerce("false", FalseClass) # => false
89
+ coerce("true", TrueClass) # => true
90
+ coerce("false", FalseClass) # => false
58
91
 
59
- * Added coercion rule from any Object to String through ruby's String(). Note
60
- that even with this coercion rule, coerce(nil, String) returns nil as that
92
+ * Added coercion rule from any Object to String through ruby's String(). Note
93
+ that even with this coercion rule, coerce(nil, String) returns nil as that
61
94
  rule has higher priority.
62
-
63
- * require('time') is automatically issued when trying to coerce a String to
64
- a Time. Time.parse is obviously needed.
95
+
96
+ * require('time') is automatically issued when trying to coerce a String to
97
+ a Time. Time.parse is obviously needed.
65
98
 
66
99
  * Myrrha::Boolean (Boolean with core extensions) is now a factored domain (see
67
- below). Therefore, it is now a true Class instance.
100
+ below). Therefore, it is now a true Class instance.
68
101
 
69
102
  ## Enhancements to the general coercion mechanism
70
103
 
71
- * An optimistic coercion is tried when a rule is encountered whose target
104
+ * An optimistic coercion is tried when a rule is encountered whose target
72
105
  domain is a super domain of the requested one. Coercion only succeeds if
73
106
  the coerced value correctly belongs to the latter domain. Example:
74
-
107
+
75
108
  rules = Myrrha.coercions do |r|
76
- r.coercion String, Numeric, lambda{|s,t| Integer(s)}
77
- end
109
+ r.coercion String, Numeric, lambda{|s,t| Integer(s)}
110
+ end
78
111
  rules.coerce("12", Integer) # => 12 in 1.1.0 while it failed in 1.0.0
79
112
  rules.coerce("12", Float) # => Myrrha::Error
80
113
 
81
- * You can now specify a coercion path, through an array of domains. For
114
+ * You can now specify a coercion path, through an array of domains. For
82
115
  example (completely contrived, of course):
83
116
 
84
117
  rules = Myrrha.coercions do |r|
85
118
  r.coercion String, Symbol, lambda{|s,t| s.to_sym }
86
119
  r.coercion Float, String, lambda{|s,t| s.to_s }
87
120
  r.coercion Integer, Float, lambda{|s,t| Float(s) }
88
- r.coercion Integer, Symbol, [Float, String]
121
+ r.coercion Integer, Symbol, [Float, String]
89
122
  end
90
123
  rules.coerce(12, Symbol) # => :"12.0" as Symbol(String(Float(12)))
91
124
 
92
- * You can now define domains through specialization by constraint (sbyc) on ruby
125
+ * You can now define domains through specialization by constraint (sbyc) on ruby
93
126
  classes, using Myrrha.domain:
94
-
127
+
95
128
  # Create a positive integer domain, as ... positive integers
96
129
  PosInt = Myrrha.domain(Integer){|i| i > 0 }
97
-
98
- Created domain is a real Class instance, that correctly responds to :===
99
- and :superclass. The feature is mainly introduced for supporting the following
130
+
131
+ Created domain is a real Class instance, that correctly responds to :===
132
+ and :superclass. The feature is mainly introduced for supporting the following
100
133
  kind of coercion scenarios (see README for more about this):
101
-
134
+
102
135
  rules = Myrrha.coercions do |r|
103
- r.coercion String, Integer, lambda{|s,t| Integer(s)}
104
- end
136
+ r.coercion String, Integer, lambda{|s,t| Integer(s)}
137
+ end
105
138
  rules.coerce("12", PosInt) # => 12
106
- rules.coerce("-12", PosInt) # => ArgumentError, "Invalid value -12 for PosInt"
139
+ rules.coerce("-12", PosInt) # => ArgumentError, "Invalid value -12 for PosInt"
107
140
 
108
141
  ## Bug fixes
109
142
 
data/README.md CHANGED
@@ -8,17 +8,17 @@
8
8
  Myrrha provides the coercion framework which is missing to Ruby, IMHO. Coercions
9
9
  are simply defined as a set of rules for converting values from source to target
10
10
  domains (in an abstract sense). As a typical and useful example, it comes bundled
11
- with a coerce() method providing a unique entry point for converting a string to
12
- a numeric, a boolean, a date, a time, an URI, and so on.
11
+ with a coerce() method providing a unique entry point for converting a string to
12
+ a numeric, a boolean, a date, a time, an URI, and so on.
13
13
 
14
14
  ### Install
15
15
 
16
16
  % [sudo] gem install myrrha
17
17
 
18
- ### Bundler & Require
18
+ ### Bundler & Require
19
19
 
20
- # Bug fixes (tiny) do not even add new default rules to coerce and
21
- # to\_ruby\_literal. Minor version can, which could break your code.
20
+ # Bug fixes (tiny) do not even add new default rules to coerce and
21
+ # to\_ruby\_literal. Minor version can, which could break your code.
22
22
  # Therefore, please always use:
23
23
  gem "myrrha", "~> 1.2.2"
24
24
 
@@ -37,13 +37,13 @@ a numeric, a boolean, a date, a time, an URI, and so on.
37
37
 
38
38
  Having a single entry point for coercing values from one data-type (typically
39
39
  a String) to another one is very useful. Unfortunately, Ruby does not provide
40
- such a unique entry point... Thanks to Myrrah, the following scenario is
40
+ such a unique entry point... Thanks to Myrrah, the following scenario is
41
41
  possible and even straightforward:
42
42
 
43
43
  require 'myrrha/with_core_ext'
44
44
  require 'myrrha/coerce'
45
45
  require 'date'
46
-
46
+
47
47
  values = ["12", "true", "2011-07-20"]
48
48
  types = [Integer, Boolean, Date]
49
49
  values.zip(types).collect do |value,domain|
@@ -53,27 +53,27 @@ possible and even straightforward:
53
53
 
54
54
  ### Implemented coercions
55
55
 
56
- Implemented coercions are somewhat conservative, and only use a subset of what
57
- ruby provides here and there. This is to avoid strangeness ala PHP... The
56
+ Implemented coercions are somewhat conservative, and only use a subset of what
57
+ ruby provides here and there. This is to avoid strangeness ala PHP... The
58
58
  general philosophy is to provide the natural coercions we apply everyday.
59
59
 
60
60
  The master rules are
61
61
 
62
- * <code>coerce(value, Domain)</code> return <code>value</code> if
62
+ * <code>coerce(value, Domain)</code> returns <code>value</code> if
63
63
  <code>belongs_to?(value, Domain)</code> is true (see last section below)
64
64
  * <code>coerce(value, Domain)</code> returns <code>Domain.coerce(value)</code>
65
65
  if the latter method exists.
66
66
  * <code>coerce("any string", Domain)</code> returns <code>Domain.parse(value)</code>
67
67
  if the latter method exists.
68
68
 
69
- The specific implemented rules are
69
+ The specific implemented rules are
70
70
 
71
71
  require 'myrrha/with_core_ext'
72
72
  require 'myrrha/coerce'
73
-
73
+
74
74
  # NilClass -> _Anything_ returns nil, always
75
75
  coerce(nil, Integer) # => nil
76
-
76
+
77
77
  # Object -> String, via ruby's String()
78
78
  coerce("hello", String) # => "hello"
79
79
  coerce(:hello, String) # => "hello"
@@ -81,38 +81,38 @@ The specific implemented rules are
81
81
  # String -> Numeric, through ruby's Integer() and Float()
82
82
  coerce("12", Integer) # => 12
83
83
  coerce("12.0", Float) # => 12.0
84
-
84
+
85
85
  # String -> Numeric is smart enough:
86
86
  coerce("12", Numeric) # => 12 (Integer)
87
87
  coerce("12.0", Numeric) # => 12.0 (Float)
88
-
88
+
89
89
  # String -> Regexp, through Regexp.compile
90
90
  coerce("[a-z]+", Regexp) # => /[a-z]+/
91
-
91
+
92
92
  # String -> Symbol, through to_sym
93
- coerce("hello", Symbol) # => :hello
94
-
93
+ coerce("hello", Symbol) # => :hello
94
+
95
95
  # String -> Boolean (hum, sorry Matz!)
96
96
  coerce("true", Boolean) # => true
97
97
  coerce("false", Boolean) # => false
98
98
  coerce("true", TrueClass) # => true
99
99
  coerce("false", FalseClass) # => false
100
-
101
- # String -> Date, through Date.parse
100
+
101
+ # String -> Date, through Date.parse
102
102
  require 'date'
103
- coerce("2011-07-20", Date) # => #<Date: 2011-07-20 (4911525/2,0,2299161)>
104
-
103
+ coerce("2011-07-20", Date) # => #<Date: 2011-07-20 (4911525/2,0,2299161)>
104
+
105
105
  # String -> Time, through Time.parse (just in time issuing of require('time'))
106
106
  coerce("2011-07-20 10:57", Time) # => 2011-07-20 10:57:00 +0200
107
-
107
+
108
108
  # String -> URI, through URI.parse
109
109
  require 'uri'
110
- coerce('http://google.com', URI) # => #<URI::HTTP:0x8281ce0 URL:http://google.com>
110
+ coerce('http://google.com', URI) # => #<URI::HTTP:0x8281ce0 URL:http://google.com>
111
111
 
112
112
  # String -> Class and Module through constant lookup
113
113
  coerce("Integer", Class) # => Integer
114
114
  coerce("Myrrha::Version", Module) # => Myrrha::Version
115
-
115
+
116
116
  # Symbol -> Class and Module through constant lookup
117
117
  coerce(:Integer, Class) # => Integer
118
118
  coerce(:Enumerable, Module) # => Enumerable
@@ -120,10 +120,10 @@ The specific implemented rules are
120
120
  ### No core extension? no problem!
121
121
 
122
122
  require 'myrrha/coerce'
123
-
123
+
124
124
  Myrrha.coerce("12", Integer) # => 12
125
125
  Myrrha.coerce("12.0", Float) # => 12.0
126
-
126
+
127
127
  Myrrha.coerce("true", Myrrha::Boolean) # => true
128
128
  # [... and so on ...]
129
129
 
@@ -140,12 +140,12 @@ method on you class; it will be used in priority.
140
140
  Foo.new(arg)
141
141
  end
142
142
  end
143
-
144
- Myrrha.coerce(:hello, Foo)
143
+
144
+ Myrrha.coerce(:hello, Foo)
145
145
  # => #<Foo:0x869eee0 @arg=:hello>
146
146
 
147
- If <code>Foo</code> is not your code and you don't want to make core extensions
148
- by adding a <code>coerce</code> class method, you can simply add new rules to
147
+ If <code>Foo</code> is not your code and you don't want to monkey patch the class
148
+ by adding a <code>coerce</code> class method, you can simply add new rules to
149
149
  Myrrha itself:
150
150
 
151
151
  Myrrha::Coerce.append do |r|
@@ -153,47 +153,47 @@ Myrrha itself:
153
153
  Foo.new(value)
154
154
  end
155
155
  end
156
-
157
- Myrrha.coerce(:hello, Foo)
156
+
157
+ Myrrha.coerce(:hello, Foo)
158
158
  # => #<Foo:0x8866f84 @arg=:hello>
159
159
 
160
- Now, doing so, the new coercion rule will be shared with all Myrrha users, which
160
+ Now, doing so, the new coercion rule will be shared with all Myrrha users, which
161
161
  might be intrusive. Why not using your own set of coercion rules?
162
162
 
163
163
  MyRules = Myrrha::Coerce.dup.append do |r|
164
164
  r.coercion(Symbol, Foo) do |value, _|
165
165
  Foo.new(value)
166
166
  end
167
- end
168
-
167
+ end
168
+
169
169
  # Myrrha.coerce is actually a shortcut for:
170
170
  Myrrha::Coerce.apply(:hello, Foo)
171
171
  # => Myrrha::Error: Unable to coerce `hello` to Foo
172
-
173
- MyRules.apply(:hello, Foo)
172
+
173
+ MyRules.apply(:hello, Foo)
174
174
  # => #<Foo:0x8b7d254 @arg=:hello>
175
175
 
176
176
  ## The <code>to\_ruby\_literal()</code> feature
177
177
 
178
- Myrrha.to_ruby_literal([:anything])
178
+ Myrrha.to_ruby_literal([:anything])
179
179
  [:anything].to_ruby_literal # with core extensions
180
180
 
181
181
  ### What for?
182
182
 
183
- <code>Object#to\_ruby\_literal</code> has a very simple specification. Given an
184
- object o that can be considered as a true _value_, the result of
185
- <code>o.to\_ruby\_literal</code> must be such that the following invariant
183
+ <code>Object#to\_ruby\_literal</code> has a very simple specification. Given an
184
+ object o that can be considered as a true _value_, the result of
185
+ <code>o.to\_ruby\_literal</code> must be such that the following invariant
186
186
  holds:
187
187
 
188
- Kernel.eval(o.to_ruby_literal) == o
188
+ Kernel.eval(o.to_ruby_literal) == o
189
189
 
190
- That is, parsing & evaluating the literal yields the same value. When generating
191
- (human-readable) ruby code, having a unique entry point that respects the
192
- specification is very useful.
190
+ That is, parsing & evaluating the literal yields the same value. When generating
191
+ (human-readable) ruby code, having a unique entry point that respects the
192
+ specification is very useful.
193
193
 
194
- For almost all ruby classes, but not all, using o.inspect respects the
194
+ For almost all ruby classes, but not all, using o.inspect respects the
195
195
  invariant. For example, the following is true:
196
-
196
+
197
197
  Kernel.eval("hello".inspect) == "hello" # => true
198
198
  Kernel.eval([1, 2, 3].inspect) == [1, 2, 3] # => true
199
199
  Kernel.eval({:key => :value}.inspect) == {:key => :value} # => true
@@ -202,19 +202,19 @@ invariant. For example, the following is true:
202
202
  Unfortunately, this is not always the case:
203
203
 
204
204
  Kernel.eval(Date.today.inspect) == Date.today
205
- # => false
205
+ # => false
206
206
  # => because Date.today.inspect yields "#<Date: 2011-07-20 ...", which is a comment
207
207
 
208
208
  ### Example
209
209
 
210
- Myrrha implements a very simple set of rules for implementing
210
+ Myrrha implements a very simple set of rules for implementing
211
211
  <code>Object#to\_ruby\_literal</code> that works:
212
212
 
213
213
  require 'date'
214
214
  require 'myrrha/with_core_ext'
215
215
  require 'myrrha/to_ruby_literal'
216
-
217
- 1.to_ruby_literal # => "1"
216
+
217
+ 1.to_ruby_literal # => "1"
218
218
  Date.today.to_ruby_literal # => "Marshal.load('...')"
219
219
  ["hello", Date.today].to_ruby_literal # => "['hello', Marshal.load('...')]"
220
220
 
@@ -222,7 +222,7 @@ Myrrha implements a best-effort strategy to return a human readable string. It
222
222
  simply fallbacks to <code>Marshal.load(...)</code> when the strategy fails:
223
223
 
224
224
  (1..10).to_ruby_literal # => "1..10"
225
-
225
+
226
226
  today = Date.today
227
227
  (today..today+1).to_ruby_literal # => "Marshal.load('...')"
228
228
 
@@ -230,7 +230,7 @@ simply fallbacks to <code>Marshal.load(...)</code> when the strategy fails:
230
230
 
231
231
  require 'date'
232
232
  require 'myrrha/to_ruby_literal'
233
-
233
+
234
234
  Myrrha.to_ruby_literal(1) # => 1
235
235
  Myrrha.to_ruby_literal(Date.today) # => Marshal.load("...")
236
236
  # [... and so on ...]
@@ -249,9 +249,9 @@ class
249
249
  "Foo.new(#{arg.inspect})"
250
250
  end
251
251
  end
252
-
252
+
253
253
  Myrrha.to_ruby_literal(Foo.new(:hello))
254
- # => "Foo.new(:hello)"
254
+ # => "Foo.new(:hello)"
255
255
 
256
256
  As with coerce, contributing your own rule to Myrrha is possible:
257
257
 
@@ -262,8 +262,8 @@ As with coerce, contributing your own rule to Myrrha is possible:
262
262
  end
263
263
 
264
264
  Myrrha.to_ruby_literal(Foo.new(:hello))
265
- # => "Foo.new(:hello)"
266
-
265
+ # => "Foo.new(:hello)"
266
+
267
267
  And building your own set of rules is possible as well:
268
268
 
269
269
  MyRules = Myrrha::ToRubyLiteral.dup.append do |r|
@@ -275,60 +275,60 @@ And building your own set of rules is possible as well:
275
275
  # Myrrha.to_ruby_literal is actually a shortcut for:
276
276
  Myrrha::ToRubyLiteral.apply(Foo.new(:hello))
277
277
  # => "Marshal.load('...')"
278
-
278
+
279
279
  MyRules.apply(Foo.new(:hello))
280
- # => "Foo.new(:hello)"
281
-
280
+ # => "Foo.new(:hello)"
281
+
282
282
  ### Limitation
283
283
 
284
284
  As the feature fallbacks to marshaling, everything which is marshalable will
285
- work. As usual, <code>to\_ruby\_literal(Proc)</code> won't work.
285
+ work. As usual, <code>to\_ruby\_literal(Proc)</code> won't work.
286
286
 
287
287
  ## The general coercion framework
288
288
 
289
289
  A set of coercion rules can simply be created from scratch as follows:
290
290
 
291
291
  Rules = Myrrha.coercions do |r|
292
-
292
+
293
293
  # `upon` rules are tried in priority if PRE holds
294
294
  r.upon(SourceDomain) do |value, requested_domain|
295
-
295
+
296
296
  # PRE: - user wants to coerce `value` to a requested_domain
297
297
  # - belongs_to?(value, SourceDomain)
298
-
298
+
299
299
  # implement the coercion or throw(:newrule)
300
300
  returned_value = something(value)
301
-
301
+
302
302
  # POST: belongs_to?(returned_value, requested_domain)
303
-
303
+
304
304
  end
305
-
305
+
306
306
  # `coercion` rules are then tried in order if PRE holds
307
307
  r.coercion(SourceDomain, TargetDomain) do |value, requested_domain|
308
-
308
+
309
309
  # PRE: - user wants to coerce `value` to a requested_domain
310
310
  # - belongs_to?(value, SourceDomain)
311
311
  # - subdomain?(TargetDomain, requested_domain)
312
-
312
+
313
313
  # implement the coercion or throw(:newrule)
314
- returned_value = something(value)
315
-
314
+ returned_value = something(value)
315
+
316
316
  # POST: returned_value belongs to requested_domain
317
-
317
+
318
318
  end
319
-
319
+
320
320
  # fallback rules are tried if everything else has failed
321
321
  r.fallback(SourceDomain) do |value, requested_domain|
322
-
322
+
323
323
  # exactly the same as upon rules
324
-
324
+
325
325
  end
326
-
326
+
327
327
  end
328
-
329
- When the user invokes <code>Rules.apply(value, domain)</code> all rules for
330
- which PRE holds are executed in order, until one succeed (chain of
331
- responsibility design pattern). This means that coercions always execute in
328
+
329
+ When the user invokes <code>Rules.apply(value, domain)</code> all rules for
330
+ which PRE holds are executed in order, until one succeed (chain of
331
+ responsibility design pattern). This means that coercions always execute in
332
332
  <code>O(number of rules)</code>.
333
333
 
334
334
  ### Specifying converters
@@ -343,7 +343,7 @@ which is passed the source value and requested target domain.
343
343
  }
344
344
  end
345
345
  convert("12", Integer)
346
-
346
+
347
347
  A converter may also be specified as an array of domains. In this case, it is
348
348
  assumed that they for a path inside the convertion graph. Consider for example
349
349
  the following coercion rules (contrived example)
@@ -354,42 +354,42 @@ the following coercion rules (contrived example)
354
354
  r.coercion Integer, Float, lambda{|s,t| Float(s) } # 3
355
355
  r.coercion Integer, Symbol, [Float, String] # 4
356
356
  end
357
-
358
- The last rule specifies a convertion path, through intermediate domains. The
357
+
358
+ The last rule specifies a convertion path, through intermediate domains. The
359
359
  complete rule specifies that applying the following path will work
360
360
 
361
361
  Integer -> Float -> String -> Symbol
362
362
  #3 #2 #1
363
-
363
+
364
364
  Indeed,
365
365
 
366
- rules.coerce(12, Symbol) # => :"12.0"
367
-
368
- ### Semantics of <code>belongs\_to?</code> and <code>subdomain?</code>
366
+ rules.coerce(12, Symbol) # => :"12.0"
369
367
 
370
- The pseudo-code given above relies on two main abstractions. Suppose the user
368
+ ### Semantics of <code>belongs\_to?</code> and <code>subdomain?</code>
369
+
370
+ The pseudo-code given above relies on two main abstractions. Suppose the user
371
371
  makes a call to <code>coerce(value, requested_domain)</code>:
372
372
 
373
373
  * <code>belongs\_to?(value, SourceDomain)</code> is true iif
374
- * <code>SourceDomain</code> is a <code>Proc</code> of arity 2, and
374
+ * <code>SourceDomain</code> is a <code>Proc</code> of arity 2, and
375
375
  <code>SourceDomain.call(value, requested_domain)</code> yields true
376
- * <code>SourceDomain</code> is a <code>Proc</code> of arity 1, and
376
+ * <code>SourceDomain</code> is a <code>Proc</code> of arity 1, and
377
377
  <code>SourceDomain.call(value)</code> yields true
378
378
  * <code>SourceDomain === value</code> yields true
379
379
 
380
380
  * <code>subdomain?(SourceDomain,TargetDomain)</code> is true iif
381
381
  * <code>SourceDomain == TargetDomain</code> yields true
382
- * TargetDomain respond to <code>:superdomain_of?</code> and answers true on
383
- SourceDomain
384
- * SourceDomain and TargetDomain are both classes and the latter is a super
385
- class of the former
386
-
382
+ * TargetDomain respond to <code>:superdomain_of?</code> and answers true on
383
+ SourceDomain
384
+ * SourceDomain and TargetDomain are both classes and the latter is a super
385
+ class of the former
386
+
387
387
  ### Advanced rule examples
388
388
 
389
389
  Rules = Myrrha.coercions do |r|
390
-
390
+
391
391
  # A 'catch-all' upon rule, always fired
392
- catch_all = lambda{|v,rd| true}
392
+ catch_all = lambda{|v,rd| true}
393
393
  r.upon(catch_all) do |value, requested_domain|
394
394
  if you_can_coerce?(value)
395
395
  # then do it!
@@ -397,19 +397,19 @@ makes a call to <code>coerce(value, requested_domain)</code>:
397
397
  throw(:next_rule)
398
398
  end
399
399
  end
400
-
400
+
401
401
  # Delegate every call to the requested domain if it responds to compile
402
- compilable = lambda{|v,rd| rd.respond_to?(:compile)}
402
+ compilable = lambda{|v,rd| rd.respond_to?(:compile)}
403
403
  r.upon(compilable) do |value, requested_domain|
404
404
  requested_domain.compile(value)
405
- end
406
-
405
+ end
406
+
407
407
  # A fallback strategy if everything else fails
408
408
  r.fallback(Object) do |value, requested_domain|
409
409
  # always fired after everything else
410
410
  # this is your last change, an Myrrha::Error will be raised if you fail
411
411
  end
412
-
412
+
413
413
  end
414
414
 
415
415
  ### Factoring domains through specialization by constraint
@@ -422,7 +422,7 @@ rules hold:
422
422
  * A sub-type can therefore be specified through a predicate on the super domain
423
423
 
424
424
  For example, "positive integers" is a sub type of "integers" where the predicate
425
- is "value > 0".
425
+ is "value > 0".
426
426
 
427
427
  Myrrha comes with a small feature allowing you to create types 'ala' SByC:
428
428
 
@@ -435,39 +435,35 @@ Myrrha comes with a small feature allowing you to create types 'ala' SByC:
435
435
  PosInt === -1 # => false
436
436
  PosInt.new(10) # => 10
437
437
  PosInt.new(-10) # => ArgumentError, "Invalid value -10 for PosInt"
438
-
438
+
439
439
  Note that the feature is very limited, and is not intended to provide a truly
440
440
  coherent typing framework. For example:
441
441
 
442
442
  10.is_a?(PosInt) # => false
443
- 10.kind_of?(PosInt) # => false
444
-
445
- Instead, Myrrha domains are only provided as an helper to build sound coercions
446
- rules easily while 1) keeping a Class-based approach to source and target
447
- domains and 2) having friendly error messages 3) really supporting true
443
+ 10.kind_of?(PosInt) # => false
444
+
445
+ Instead, Myrrha domains are only provided as an helper to build sound coercions
446
+ rules easily while 1) keeping a Class-based approach to source and target
447
+ domains and 2) having friendly error messages 3) really supporting true
448
448
  reasoning on types and value:
449
449
 
450
450
  # Only a rule that converts String to Integer
451
451
  rules = Myrrha.coercions do |r|
452
- r.coercion String, Integer, lambda{|s,t| Integer(s)}
453
- end
454
-
452
+ r.coercion String, Integer, lambda{|s,t| Integer(s)}
453
+ end
454
+
455
455
  # it succeeds on both integers and positive integers
456
456
  rules.coerce("12", Integer) # => 12
457
457
  rules.coerce("12", PosInt) # => 12
458
-
458
+
459
459
  # and correctly fails in each case!
460
460
  rules.coerce("-12", Integer) # => -12
461
461
  rules.coerce("-12", PosInt) # => ArgumentError, "Invalid value -12 for PosInt"
462
462
 
463
- Note that if you want to provide additional tooling to your factored domain,
463
+ Note that if you want to provide additional tooling to your factored domain,
464
464
  the following way of creating them also works:
465
465
 
466
466
  class PosInt < Integer
467
- extend Myrrha::Domain
468
-
469
- def self.predicate
470
- @predicate ||= lambda{|i| i > 0}
471
- end
472
-
467
+ extend Myrrha::Domain.new(Integer, [], lambda{|i| i > 0})
468
+
473
469
  end