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.
Files changed (49) hide show
  1. data/CHANGELOG.md +5 -0
  2. data/Gemfile +2 -0
  3. data/Gemfile.lock +41 -0
  4. data/LICENCE.md +22 -0
  5. data/Manifest.txt +13 -0
  6. data/README.md +337 -0
  7. data/Rakefile +23 -0
  8. data/examples/String#toXXX.rb +40 -0
  9. data/examples/coerce.rb +26 -0
  10. data/examples/coerce_foo.rb +12 -0
  11. data/examples/coerce_foo2.rb +17 -0
  12. data/examples/coerce_foo3.rb +23 -0
  13. data/examples/coerce_intro.rb +10 -0
  14. data/examples/coerce_noext.rb +6 -0
  15. data/examples/examples_helper.rb +17 -0
  16. data/examples/friendly_but_safe_api.rb +73 -0
  17. data/examples/to_ruby_literal.rb +16 -0
  18. data/examples/to_ruby_literal_foo.rb +14 -0
  19. data/examples/to_ruby_literal_foo2.rb +17 -0
  20. data/examples/to_ruby_literal_foo3.rb +21 -0
  21. data/examples/to_ruby_literal_noext.rb +5 -0
  22. data/lib/myrrha/coerce.rb +93 -0
  23. data/lib/myrrha/loader.rb +0 -0
  24. data/lib/myrrha/to_ruby_literal.rb +76 -0
  25. data/lib/myrrha/version.rb +14 -0
  26. data/lib/myrrha/with_core_ext.rb +2 -0
  27. data/lib/myrrha.rb +295 -0
  28. data/myrrha.gemspec +191 -0
  29. data/myrrha.noespec +37 -0
  30. data/spec/coercions/test_append.rb +11 -0
  31. data/spec/coercions/test_belongs_to.rb +29 -0
  32. data/spec/coercions/test_convert.rb +23 -0
  33. data/spec/coercions/test_dup.rb +21 -0
  34. data/spec/coercions/test_subdomain.rb +11 -0
  35. data/spec/shared/a_value.rb +33 -0
  36. data/spec/spec_helper.rb +34 -0
  37. data/spec/test_assumptions.rb +18 -0
  38. data/spec/test_coerce.rb +119 -0
  39. data/spec/test_myrrha.rb +87 -0
  40. data/spec/test_to_ruby_literal.rb +19 -0
  41. data/spec/test_value.rb +6 -0
  42. data/tasks/debug_mail.rake +78 -0
  43. data/tasks/debug_mail.txt +13 -0
  44. data/tasks/examples.rake +13 -0
  45. data/tasks/gem.rake +68 -0
  46. data/tasks/spec_test.rake +79 -0
  47. data/tasks/unit_test.rake +77 -0
  48. data/tasks/yard.rake +51 -0
  49. metadata +195 -0
data/myrrha.gemspec ADDED
@@ -0,0 +1,191 @@
1
+ # We require your library, mainly to have access to the VERSION number.
2
+ # Feel free to set $version manually.
3
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
4
+ require "myrrha/version"
5
+ $version = Myrrha::Version.to_s
6
+
7
+ #
8
+ # This is your Gem specification. Default values are provided so that your library
9
+ # should be correctly packaged given what you have described in the .noespec file.
10
+ #
11
+ Gem::Specification.new do |s|
12
+
13
+ ################################################################### ABOUT YOUR GEM
14
+
15
+ # Gem name (required)
16
+ s.name = "myrrha"
17
+
18
+ # Gem version (required)
19
+ s.version = $version
20
+
21
+ # A short summary of this gem
22
+ #
23
+ # This is displayed in `gem list -d`.
24
+ s.summary = "Myrrha provides the coercion framework which is missing to Ruby, IMHO."
25
+
26
+ # A long description of this gem (required)
27
+ #
28
+ # The description should be more detailed than the summary. For example,
29
+ # you might wish to copy the entire README into the description.
30
+ s.description = "Myrrha provides the coercion framework which is missing to Ruby, IMHO. Coercions\nare simply defined as a set of rules for converting values from source to target\ndomains (in an abstract sense). As a typical and useful example, it comes bundled\nwith a coerce() method providing a unique entry point for converting a string to \na numeric, a boolean, a date, a time, an URI, and so on. "
31
+
32
+ # The URL of this gem home page (optional)
33
+ s.homepage = "http://rubydoc.info/github/blambeau/myrrha/master/frames"
34
+
35
+ # Gem publication date (required but auto)
36
+ #
37
+ # Today is automatically used by default, uncomment only if
38
+ # you know what you do!
39
+ #
40
+ # s.date = Time.now.strftime('%Y-%m-%d')
41
+
42
+ # The license(s) for the library. Each license must be a short name, no
43
+ # more than 64 characters.
44
+ #
45
+ # s.licences = %w{}
46
+
47
+ # The rubyforge project this gem lives under (optional)
48
+ #
49
+ # s.rubyforge_project = nil
50
+
51
+ ################################################################### ABOUT THE AUTHORS
52
+
53
+ # The list of author names who wrote this gem.
54
+ #
55
+ # If you are providing multiple authors and multiple emails they should be
56
+ # in the same order.
57
+ #
58
+ s.authors = ["Bernard Lambeau"]
59
+
60
+ # Contact emails for this gem
61
+ #
62
+ # If you are providing multiple authors and multiple emails they should be
63
+ # in the same order.
64
+ #
65
+ # NOTE: Somewhat strangly this attribute is always singular!
66
+ # Don't replace by s.emails = ...
67
+ s.email = ["blambeau@gmail.com"]
68
+
69
+ ################################################################### PATHS, FILES, BINARIES
70
+
71
+ # Paths in the gem to add to $LOAD_PATH when this gem is
72
+ # activated (required).
73
+ #
74
+ # The default 'lib' is typically sufficient.
75
+ s.require_paths = ["lib"]
76
+
77
+ # Files included in this gem.
78
+ #
79
+ # By default, we take all files included in the Manifest.txt file on root
80
+ # of the project. Entries of the manifest are interpreted as Dir[...]
81
+ # patterns so that lazy people may use wilcards like lib/**/*
82
+ #
83
+ here = File.expand_path(File.dirname(__FILE__))
84
+ s.files = File.readlines(File.join(here, 'Manifest.txt')).
85
+ inject([]){|files, pattern| files + Dir[File.join(here, pattern.strip)]}.
86
+ collect{|x| x[(1+here.size)..-1]}
87
+
88
+ # Test files included in this gem.
89
+ #
90
+ s.test_files = Dir["test/**/*"] + Dir["spec/**/*"]
91
+
92
+ # The path in the gem for executable scripts (optional)
93
+ #
94
+ s.bindir = "bin"
95
+
96
+ # Executables included in the gem.
97
+ #
98
+ s.executables = (Dir["bin/*"]).collect{|f| File.basename(f)}
99
+
100
+ ################################################################### REQUIREMENTS & INSTALL
101
+ # Remember the gem version requirements operators and schemes:
102
+ # = Equals version
103
+ # != Not equal to version
104
+ # > Greater than version
105
+ # < Less than version
106
+ # >= Greater than or equal to
107
+ # <= Less than or equal to
108
+ # ~> Approximately greater than
109
+ #
110
+ # Don't forget to have a look at http://lmgtfy.com/?q=Ruby+Versioning+Policies
111
+ # for setting your gem version.
112
+ #
113
+ # For your requirements to other gems, remember that
114
+ # ">= 2.2.0" (optimistic: specify minimal version)
115
+ # ">= 2.2.0", "< 3.0" (pessimistic: not greater than the next major)
116
+ # "~> 2.2" (shortcut for ">= 2.2.0", "< 3.0")
117
+ # "~> 2.2.0" (shortcut for ">= 2.2.0", "< 2.3.0")
118
+ #
119
+
120
+ #
121
+ # One call to add_dependency('gem_name', 'gem version requirement') for each
122
+ # runtime dependency. These gems will be installed with your gem.
123
+ # One call to add_development_dependency('gem_name', 'gem version requirement')
124
+ # for each development dependency. These gems are required for developers
125
+ #
126
+ s.add_development_dependency("rake", "~> 0.9.2")
127
+ s.add_development_dependency("bundler", "~> 1.0")
128
+ s.add_development_dependency("rspec", "~> 2.6.0")
129
+ s.add_development_dependency("yard", "~> 0.7.2")
130
+ s.add_development_dependency("bluecloth", "~> 2.0.9")
131
+ s.add_development_dependency("wlang", "~> 0.10.1")
132
+ s.add_development_dependency("noe", "~> 1.3.0")
133
+
134
+
135
+ # The version of ruby required by this gem
136
+ #
137
+ # Uncomment and set this if your gem requires specific ruby versions.
138
+ #
139
+ # s.required_ruby_version = ">= 0"
140
+
141
+ # The RubyGems version required by this gem
142
+ #
143
+ # s.required_rubygems_version = ">= 0"
144
+
145
+ # The platform this gem runs on. See Gem::Platform for details.
146
+ #
147
+ # s.platform = nil
148
+
149
+ # Extensions to build when installing the gem.
150
+ #
151
+ # Valid types of extensions are extconf.rb files, configure scripts
152
+ # and rakefiles or mkrf_conf files.
153
+ #
154
+ s.extensions = []
155
+
156
+ # External (to RubyGems) requirements that must be met for this gem to work.
157
+ # It’s simply information for the user.
158
+ #
159
+ s.requirements = nil
160
+
161
+ # A message that gets displayed after the gem is installed
162
+ #
163
+ # Uncomment and set this if you want to say something to the user
164
+ # after gem installation
165
+ #
166
+ s.post_install_message = nil
167
+
168
+ ################################################################### SECURITY
169
+
170
+ # The key used to sign this gem. See Gem::Security for details.
171
+ #
172
+ # s.signing_key = nil
173
+
174
+ # The certificate chain used to sign this gem. See Gem::Security for
175
+ # details.
176
+ #
177
+ # s.cert_chain = []
178
+
179
+ ################################################################### RDOC
180
+
181
+ # An ARGV style array of options to RDoc
182
+ #
183
+ # See 'rdoc --help' about this
184
+ #
185
+ s.rdoc_options = []
186
+
187
+ # Extra files to add to RDoc such as README
188
+ #
189
+ s.extra_rdoc_files = Dir["README.md"] + Dir["CHANGELOG.md"] + Dir["LICENCE.md"]
190
+
191
+ end
data/myrrha.noespec ADDED
@@ -0,0 +1,37 @@
1
+ # Noe template for ruby gem libraries (https://github.com/blambeau/noe) - short version
2
+ # Run 'noe show-spec' and 'noe help show-spec' for additional details.
3
+ template-info:
4
+ name: "ruby"
5
+ version: 1.3.0
6
+ variables:
7
+ lower:
8
+ myrrha
9
+ upper:
10
+ Myrrha
11
+ version:
12
+ 1.0.0
13
+ summary: |-
14
+ Myrrha provides the coercion framework which is missing to Ruby, IMHO.
15
+ description: |-
16
+ Myrrha provides the coercion framework which is missing to Ruby, IMHO. Coercions
17
+ are simply defined as a set of rules for converting values from source to target
18
+ domains (in an abstract sense). As a typical and useful example, it comes bundled
19
+ with a coerce() method providing a unique entry point for converting a string to
20
+ a numeric, a boolean, a date, a time, an URI, and so on.
21
+ authors:
22
+ - {name: Bernard Lambeau, email: blambeau@gmail.com}
23
+ links:
24
+ - http://rubydoc.info/github/blambeau/myrrha/master/frames
25
+ - http://github.com/blambeau/myrrha
26
+ - http://rubygems.org/gems/myrrha
27
+ dependencies:
28
+ - {name: rake, version: "~> 0.9.2", groups: [development]}
29
+ - {name: bundler, version: "~> 1.0", groups: [development]}
30
+ - {name: rspec, version: "~> 2.6.0", groups: [development]}
31
+ - {name: yard, version: "~> 0.7.2", groups: [development]}
32
+ - {name: bluecloth, version: "~> 2.0.9", groups: [development]}
33
+ - {name: wlang, version: "~> 0.10.1", groups: [development]}
34
+ - {name: noe, version: "~> 1.3.0", groups: [development]}
35
+ rake_tasks:
36
+ spec_test:
37
+ pattern: spec/**/test_*.rb
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+ module Myrrha
3
+ describe "Coercions#append" do
4
+ let(:rules){ Coercions.new }
5
+
6
+ it "should return the rules" do
7
+ rules.append{|r| }.should eq(rules)
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+ module Myrrha
3
+ describe "Coercions#belongs_to?" do
4
+ let(:rules){ Coercions.new }
5
+
6
+ specify "with a class" do
7
+ rules.belongs_to?(12, Integer).should be_true
8
+ end
9
+
10
+ specify "with a superclass" do
11
+ rules.belongs_to?(12, Numeric).should be_true
12
+ end
13
+
14
+ specify "with a proc or arity 1" do
15
+ rules.belongs_to?(12, lambda{|x| x>10}).should be_true
16
+ rules.belongs_to?(12, lambda{|x| x<10}).should be_false
17
+ end
18
+
19
+ specify "with a proc or arity 2" do
20
+ got = nil
21
+ l = lambda{|x,t| got = t; t == l }
22
+ rules.belongs_to?(12, l).should be_true
23
+ got.should eq(l)
24
+ rules.belongs_to?(12, l, :nosuch).should be_false
25
+ got.should eq(:nosuch)
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+ module Myrrha
3
+ describe "Coercions#convert" do
4
+ let(:graph){ Coercions.new }
5
+
6
+ subject{ graph.send(:convert, "value", String, converter) }
7
+
8
+ describe "when passed a proc of arity 2" do
9
+ let(:converter){ lambda{|v,t| [v,t]} }
10
+ it{ should eq(["value", String]) }
11
+ end
12
+
13
+ describe "when passed an object that respond to call" do
14
+ let(:converter){
15
+ o = Object.new
16
+ def o.call(arg, t); [arg, t]; end
17
+ o
18
+ }
19
+ it{ should eq(["value", String]) }
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+ module Myrrha
3
+ describe "Coercions#dup" do
4
+ let(:rules){ Coercions.new{|r|
5
+ r.coercion String, Integer, lambda{|s,t| Integer(s)}
6
+ }}
7
+
8
+ it "should duplicate the rules" do
9
+ rules.dup.coerce("12", Integer).should eql(12)
10
+ end
11
+
12
+ it "should not touch the original" do
13
+ dupped = rules.dup.append do |r|
14
+ r.coercion String, Float, lambda{|s,t| Float(s)}
15
+ end
16
+ dupped.coerce("12", Float).should eql(12.0)
17
+ lambda{ rules.coerce("12", Float) }.should raise_error(Myrrha::Error)
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+ module Myrrha
3
+ describe "Coercions#subdomain?" do
4
+ let(:graph){ Coercions.new }
5
+
6
+ specify {
7
+ graph.subdomain?(Symbol, Object).should be_true
8
+ }
9
+
10
+ end
11
+ end
@@ -0,0 +1,33 @@
1
+ shared_examples_for "a value" do
2
+
3
+ def dup(val)
4
+ Kernel.eval(val.to_ruby_literal)
5
+ end
6
+
7
+ it "should implement == correctly" do
8
+ subject.should eq(dup(subject))
9
+ end
10
+
11
+ it "should implement eql? correctly" do
12
+ {subject => true, dup(subject) => false}.size.should eq(1)
13
+ end
14
+
15
+ it "should implement class.parse / #to_s correctly" do
16
+ if subject.class.respond_to?(:parse) && subject.respond_to?(:to_s)
17
+ begin
18
+ subject.class.parse(subject.to_s).should eq(subject)
19
+ rescue
20
+ t1 = subject.class.parse(subject.to_s)
21
+ t2 = subject.class.parse(subject.to_s)
22
+ t1.should eq(t2)
23
+ end
24
+ end
25
+ end
26
+
27
+ it "should implement Kernel.eval / to_ruby_literal correctly" do
28
+ if subject.respond_to?(:to_ruby_literal)
29
+ Kernel.eval(subject.to_ruby_literal).should eq(subject)
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,34 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'myrrha/with_core_ext'
3
+ require 'myrrha/coerce'
4
+ require 'myrrha/to_ruby_literal'
5
+ require 'date'
6
+ require 'time'
7
+ require 'shared/a_value'
8
+
9
+ unless defined?(SAFE_VALUES)
10
+ SAFE_VALUES = {
11
+ NilClass => [ nil ],
12
+ TrueClass => [ true ],
13
+ FalseClass => [ false ],
14
+ Fixnum => [ -(2**(0.size * 8 - 2)), -1, 0, 1, 10, (2**(0.size * 8 - 2) - 1)],
15
+ Bignum => [ -(2**(0.size * 8 - 2)) - 1, (2**(0.size * 8 - 2)) ],
16
+ Float => [ -0.10, 0.0, 0.10 ],
17
+ String => ['', 'hello'],
18
+ Symbol => [ :hello, :"s-b-y-c", :"12" ],
19
+ Class => [ Integer, ::Struct::Tms ],
20
+ Module => [ Kernel, Myrrha ],
21
+ Regexp => [ /a-z/, /^$/, /\s*/, /[a-z]{15}/ ],
22
+ Range => [ 0..10, 0...10 ],
23
+ Array => [ [], [nil], [1, "hello"] ],
24
+ Hash => [ {}, {1 => 2, :hello => "world"} ]
25
+ }
26
+ UNSAFE_VALUES = {
27
+ Date => [ Date.today ],
28
+ Time => [ Time.now ],
29
+ Array => [ [Date.today, Time.now] ],
30
+ Hash => [ {Date.today => Time.now} ],
31
+ Range => [ Date.today..(Date.today+1) ]
32
+ }
33
+ VALUES = SAFE_VALUES.values.inject([], :+) + UNSAFE_VALUES.values.inject([], :+)
34
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+ describe "Ruby assumptions" do
3
+
4
+ describe "Proc#arity" do
5
+ specify{
6
+ lambda{|a| }.arity.should eq(1)
7
+ lambda{|a,b| }.arity.should eq(2)
8
+ }
9
+ end
10
+
11
+ class Object
12
+ def no_such_myrrha_method
13
+ end
14
+ end if false
15
+
16
+ specify{ Object.should_not respond_to(:no_such_myrrha_method) }
17
+
18
+ end
@@ -0,0 +1,119 @@
1
+ require 'spec_helper'
2
+ describe "::Ruby's coercion " do
3
+
4
+ describe "from NilClass" do
5
+ it "should always return nil" do
6
+ coerce(nil, Integer).should be_nil
7
+ coerce(nil, Date).should be_nil
8
+ end
9
+ end
10
+
11
+ describe "to Integer" do
12
+ specify "from Integer" do
13
+ coerce(12, Integer).should eql(12)
14
+ end
15
+ specify "from String" do
16
+ coerce("12", Integer).should eql(12)
17
+ coerce("-12", Integer).should eql(-12)
18
+ coerce("0", Integer).should eql(0)
19
+ end
20
+ specify "on error" do
21
+ lambda{coerce("abc", Integer)}.should raise_error(Myrrha::Error)
22
+ end
23
+ end
24
+
25
+ describe "to Float" do
26
+ specify "from Float" do
27
+ coerce(12.2, Float).should eql(12.2)
28
+ end
29
+ specify "from Integer" do
30
+ coerce(0, Float).should eql(0.0)
31
+ coerce(12, Float).should eql(12.0)
32
+ coerce(-12, Float).should eql(-12.0)
33
+ end
34
+ specify "from String" do
35
+ coerce("12.2", Float).should eql(12.2)
36
+ coerce("0", Float).should eql(0.0)
37
+ coerce("0.0", Float).should eql(0.0)
38
+ coerce("-12.2", Float).should eql(-12.2)
39
+ end
40
+ specify "on error" do
41
+ lambda{coerce("abc", Float)}.should raise_error(Myrrha::Error)
42
+ end
43
+ end
44
+
45
+ describe "to Numeric" do
46
+ specify "from String" do
47
+ coerce("12", Numeric).should eql(12)
48
+ coerce("12.2", Numeric).should eql(12.2)
49
+ end
50
+ end
51
+
52
+ describe "to Boolean" do
53
+ specify "from Boolean" do
54
+ coerce(true, Boolean).should eql(true)
55
+ coerce(false, Boolean).should eql(false)
56
+ end
57
+ specify "from String" do
58
+ coerce("true", Boolean).should eql(true)
59
+ coerce("false", Boolean).should eql(false)
60
+ end
61
+ specify "on error" do
62
+ lambda{coerce("abc", Boolean)}.should raise_error(Myrrha::Error)
63
+ end
64
+ end
65
+
66
+ describe "to Date" do
67
+ let(:expected){ Date.parse("2011-07-20") }
68
+ specify "from String" do
69
+ coerce("2011-07-20", Date).should eql(expected)
70
+ coerce("2011/07/20", Date).should eql(expected)
71
+ end
72
+ end
73
+
74
+ describe "to Time" do
75
+ let(:expected){ Time.parse("2011-07-20 10:53") }
76
+ specify "from String" do
77
+ coerce("2011-07-20 10:53", Time).should eql(expected)
78
+ end
79
+ end
80
+
81
+ describe "to Symbol" do
82
+ specify "from Symbol" do
83
+ coerce(:hello, Symbol).should eql(:hello)
84
+ end
85
+ specify "from String" do
86
+ coerce("hello", Symbol).should eql(:hello)
87
+ end
88
+ end
89
+
90
+ describe "to Regexp" do
91
+ specify "from Regexp" do
92
+ coerce(/[a-z]+/, Regexp).should eql(/[a-z]+/)
93
+ end
94
+ specify "from String" do
95
+ coerce("[a-z]+", Regexp).should eql(/[a-z]+/)
96
+ end
97
+ end
98
+
99
+ describe "to URI" do
100
+ require 'uri'
101
+ specify "from String" do
102
+ coerce("http://www.google.com/", URI).should eql(URI.parse("http://www.google.com/"))
103
+ end
104
+ end
105
+
106
+ specify "to a class that respond to coerce" do
107
+ class Coerceable
108
+ def self.coerce(val)
109
+ [:coerced, val]
110
+ end
111
+ end
112
+ coerce("hello", Coerceable).should eq([:coerced, "hello"])
113
+ end
114
+
115
+ specify "otherwise" do
116
+ lambda{ coerce("hallo", Myrrha) }.should raise_error(Myrrha::Error)
117
+ end
118
+
119
+ end
@@ -0,0 +1,87 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+ describe Myrrha do
3
+
4
+ it "should have a version number" do
5
+ Myrrha.const_defined?(:VERSION).should be_true
6
+ end
7
+
8
+ it "should provide the abitity to define a coercion rules" do
9
+ rules = Myrrha.coercions do |g|
10
+ g.coercion String, Integer, lambda{|s,t| Integer(s)}
11
+ g.coercion String, Float, lambda{|s,t| Float(s) }
12
+ end
13
+ rules.coerce(12, Integer).should eq(12)
14
+ rules.coerce("12", Integer).should eq(12)
15
+ rules.coerce(12.2, Float).should eq(12.2)
16
+ rules.coerce("12.2", Float).should eq(12.2)
17
+ rules.coerce("12", Numeric).should eq(12)
18
+ rules.coerce("12.2", Numeric).should eq(12.2)
19
+ lambda{
20
+ rules.coerce(true, Integer)
21
+ }.should raise_error(Myrrha::Error, "Unable to coerce `true` to Integer")
22
+ lambda{
23
+ rules.coerce("12.2", Integer)
24
+ }.should raise_error(Myrrha::Error, /^Unable to coerce `12.2` to Integer \(invalid value /)
25
+ end
26
+
27
+ it "should support upon rules" do
28
+ rules = Myrrha.coercions do |g|
29
+ g.coercion(Integer, Symbol){|s,t| :coercion}
30
+ g.upon(lambda{|s| s<0}){|s,t| :upon}
31
+ end
32
+ rules.coerce(12, Symbol).should eq(:coercion)
33
+ rules.coerce(-12, Symbol).should eq(:upon)
34
+ end
35
+
36
+ it "should support fallback rules" do
37
+ rules = Myrrha.coercions do |g|
38
+ g.fallback String, lambda{|s,t| :world}
39
+ end
40
+ rules.coerce("hello", Symbol).should eq(:world)
41
+ end
42
+
43
+ it "should support using matchers" do
44
+ ArrayOfSymbols = proc{|val| val.is_a?(Array) && val.all?{|x| Symbol===x}}
45
+ rules = Myrrha.coercions do |g|
46
+ g.coercion ArrayOfSymbols, String, lambda{|x,t| x.join(', ')}
47
+ end
48
+ rules.coerce([:a, :b], ArrayOfSymbols).should eq([:a, :b])
49
+ rules.coerce([:a, :b], String).should eq("a, b")
50
+ end
51
+
52
+ it "should support using any object that respond to call as converter" do
53
+ converter = Object.new
54
+ def converter.call(arg, t); [arg, t]; end
55
+ rules = Myrrha.coercions do |g|
56
+ g.coercion String, Symbol, converter
57
+ end
58
+ rules.coerce("hello", Symbol).should eq(["hello", Symbol])
59
+ end
60
+
61
+ it "should support adding rules later" do
62
+ rules = Myrrha.coercions do |c|
63
+ c.coercion String, Symbol, lambda{|s,t| s.to_sym}
64
+ c.fallback Object, lambda{|s,t| :fallback}
65
+ end
66
+ rules.coerce("hello", Symbol).should eq(:hello)
67
+ rules.coerce(12, Symbol).should eq(:fallback)
68
+
69
+ rules.append do |c|
70
+ c.coercion Integer, Symbol, lambda{|s,t| s.to_s.to_sym}
71
+ end
72
+ rules.coerce(12, Symbol).should eq(:"12")
73
+ rules.coerce(true, Symbol).should eq(:fallback)
74
+ end
75
+
76
+ it "should support adding rules before" do
77
+ rules = Myrrha.coercions do |c|
78
+ c.coercion String, Symbol, lambda{|s,t| s.to_sym}
79
+ end
80
+ rules.coerce("hello", Symbol).should eq(:hello)
81
+ rules.prepend do |c|
82
+ c.coercion String, Symbol, lambda{|s,t| s.to_s.upcase.to_sym}
83
+ end
84
+ rules.coerce("hello", Symbol).should eq(:HELLO)
85
+ end
86
+
87
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+ describe "to_ruby_literal" do
3
+
4
+ VALUES.each do |value|
5
+ describe "on #{value.inspect}" do
6
+ specify{ Kernel.eval(value.to_ruby_literal).should eq(value) }
7
+ end
8
+ end
9
+
10
+ it "should work on objects that implement to_ruby_literal" do
11
+ class ToRubyLiteralizable
12
+ def to_ruby_literal
13
+ :foo
14
+ end
15
+ end
16
+ Myrrha.to_ruby_literal(ToRubyLiteralizable.new).should eq(:foo)
17
+ end
18
+
19
+ end
@@ -0,0 +1,6 @@
1
+ VALUES.each do |value|
2
+ describe "#{value} (#{value.class})" do
3
+ subject{ value }
4
+ it_should_behave_like "a value"
5
+ end
6
+ end