myrrha 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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