must 0.2.1

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 (5) hide show
  1. data/README +132 -0
  2. data/Rakefile +48 -0
  3. data/lib/must/rule.rb +86 -0
  4. data/lib/must.rb +12 -0
  5. metadata +70 -0
data/README ADDED
@@ -0,0 +1,132 @@
1
+ Must
2
+ ====
3
+
4
+ add Object#must method to constrain its origin and conversions
5
+
6
+ # can write like this
7
+ num = params[:num].to_i.must.match(1..300) {10}
8
+
9
+ # rather than
10
+ num = params[:num].to_i
11
+ num = 10 unless (1..300) === num
12
+
13
+
14
+ Testing Methods
15
+ ===============
16
+
17
+ be : check whether object equals to the argument
18
+ kind_of : check whether object is a kind of the argument
19
+ coerced : check whether object can be coerced to the argument
20
+ blank : check whether object is blank?
21
+ exist : check whether object is not nil (NOTE: false is ok)
22
+
23
+
24
+ Logical Methods
25
+ ===============
26
+
27
+ not : logical NOT
28
+
29
+
30
+ Nop Methods
31
+ ===========
32
+
33
+ a : return self
34
+ an : return self
35
+
36
+ These effect nothing but exist only for English grammar.
37
+
38
+
39
+ Basic Examples
40
+ ==============
41
+
42
+ # test its value exactly
43
+ 1.must.be 1 # => 1
44
+ [1,2,3].must.be [1,2,3] # => [1,2,3]
45
+
46
+ # exceptions
47
+ 1.must.be [] # Must::Invalid exception
48
+ 1.must.be([]) {:ng} # => :ng
49
+ 1.must.be(1) {:ng} # => 1
50
+
51
+ # as default value
52
+ name = params[:name].must.not.be.blank{ "No name" }
53
+
54
+ # existing test
55
+ 1.must.exist # => 1
56
+ nil.must.exist # Must::Invalid exception
57
+ false.must.exist # => false
58
+
59
+ # test class : ensures that a class of the object is one of given arguments
60
+ 1.must.be.kind_of(Integer) # => 1
61
+ 1.must.be.kind_of(Integer, Array) # => 1
62
+ [].must.be.kind_of(Integer, Array) # => []
63
+ 1.must.be.kind_of(String, Array) # Must::Invalid: expected String/Array but got Fixnum
64
+
65
+ # coercing : looks like kind_of except converting its value if possible
66
+ 1.must.be.coerced(Integer, String => proc{|val| val.to_i}) # => 1
67
+ "1".must.be.coerced(Integer, String => proc{|val| val.to_i}) # => 1
68
+ "1".must.be.coerced(Integer, String => :to_i) # => 1 (NOTE: inline Symbol means sending the method)
69
+ "1".must.be.coerced(Integer, Symbol, String => proc{:to_i}) # => :to_i (NOTE: use proc to return Symbol itself)
70
+
71
+
72
+ Actual Examples
73
+ ===============
74
+
75
+ 1)
76
+
77
+ normal code:
78
+
79
+ def set_reader(reader)
80
+ if reader.is_a?(CSV::Reader)
81
+ @reader = reader
82
+ elsif file.is_a?(String)
83
+ @reader = CSV::Reader.create(i)
84
+ elsif file.is_a?(Pathname)
85
+ @reader = CSV::Reader.create(reader.read)
86
+ else
87
+ raise 'invalid reader'
88
+ end
89
+ end
90
+
91
+ refactor above code with must plugin
92
+
93
+ def set_reader(reader)
94
+ @reader = reader.must.be.coerced(CSV::Reader, Pathname=>:read, String=>{|i| CSV::Reader.create(i)}) {raise 'invalid reader'}
95
+ end
96
+
97
+ 2)
98
+
99
+ class DateFolder
100
+ def initialize(date)
101
+ @date = date.must.be.coerced(Date, String=>proc{|i| Date.new(*i.scan(/\d+/).map{|i|i.to_i})})
102
+ end
103
+ end
104
+
105
+ # this can accept both formats
106
+
107
+ DateFolder.new Date.today
108
+ DateFolder.new "2008-12-9"
109
+
110
+
111
+ Install
112
+ =======
113
+
114
+ gem install maiha-must
115
+ # add source http://gems.github.com
116
+
117
+ % irb -r rubygems -r must
118
+ irb(main):001:0> 1.must.be 1
119
+ => 1
120
+
121
+
122
+ Github
123
+ ======
124
+
125
+ http://github.com/maiha/must
126
+
127
+
128
+ Author
129
+ ======
130
+
131
+ maiha@wota.jp
132
+
data/Rakefile ADDED
@@ -0,0 +1,48 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+
4
+ GEM_NAME = "must"
5
+ AUTHOR = "maiha"
6
+ EMAIL = "maiha@wota.jp"
7
+ HOMEPAGE = "http://github.com/maiha/must"
8
+ SUMMARY = "constraint plugin"
9
+ GEM_VERSION = "0.2.1"
10
+
11
+ spec = Gem::Specification.new do |s|
12
+ s.rubyforge_project = 'asakusarb'
13
+ s.executables = []
14
+ s.name = GEM_NAME
15
+ s.version = GEM_VERSION
16
+ s.platform = Gem::Platform::RUBY
17
+ s.has_rdoc = true
18
+ s.extra_rdoc_files = ["README"]
19
+ s.summary = SUMMARY
20
+ s.description = s.summary
21
+ s.author = AUTHOR
22
+ s.email = EMAIL
23
+ s.homepage = HOMEPAGE
24
+ s.require_path = 'lib'
25
+ s.files = %w(README Rakefile) + Dir.glob("{lib,spec,app,public,stubs}/**/*")
26
+ end
27
+
28
+ Rake::GemPackageTask.new(spec) do |pkg|
29
+ pkg.gem_spec = spec
30
+ end
31
+
32
+ desc "Install the gem"
33
+ task :install do
34
+ Merb::RakeHelper.install(GEM_NAME, :version => GEM_VERSION)
35
+ end
36
+
37
+ desc "Uninstall the gem"
38
+ task :uninstall do
39
+ Merb::RakeHelper.uninstall(GEM_NAME, :version => GEM_VERSION)
40
+ end
41
+
42
+ desc "Create a gemspec file"
43
+ task :gemspec do
44
+ File.open("#{GEM_NAME}.gemspec", "w") do |file|
45
+ file.puts spec.to_ruby
46
+ end
47
+ end
48
+
data/lib/must/rule.rb ADDED
@@ -0,0 +1,86 @@
1
+ require 'set'
2
+
3
+ module Must
4
+ class Rule
5
+ attr_reader :object
6
+
7
+ def initialize(object)
8
+ @object = object
9
+ @not = false
10
+ end
11
+
12
+ def a() self end
13
+ def an() self end
14
+
15
+ def not
16
+ @not = ! @not
17
+ return self
18
+ end
19
+
20
+ def be(*args, &block)
21
+ if args.empty?
22
+ self
23
+ else
24
+ valid?(object == args.shift, &block)
25
+ end
26
+ end
27
+
28
+ def empty(&block)
29
+ valid?(object.empty?, &block)
30
+ end
31
+
32
+ def blank(&block)
33
+ valid?(object.blank?, &block)
34
+ end
35
+
36
+ def exist(&block)
37
+ self.not()
38
+ be(nil, &block)
39
+ end
40
+
41
+ def kind_of(*targets)
42
+ valid?(targets.any?{|klass| object.is_a? klass}) {
43
+ target = targets.map{|i| i.name}.join('/')
44
+ raise Invalid, "expected #{target} but got #{object.class}"
45
+ }
46
+ end
47
+
48
+ def one_of(target, &block)
49
+ valid?(target === @object, &block)
50
+ end
51
+
52
+ def valid?(condition, &block)
53
+ if condition ^ @not
54
+ object
55
+ else
56
+ block_or_throw(&block)
57
+ end
58
+ end
59
+
60
+ def block_or_throw(&block)
61
+ if block
62
+ block.call
63
+ else
64
+ raise Invalid
65
+ end
66
+ end
67
+
68
+ def coerced(*types, &block)
69
+ coecings ||= types.last.is_a?(Hash) ? types.pop : {}
70
+ already_coerced ||= Set.new
71
+ kind_of(*types)
72
+ rescue Invalid
73
+ block_or_throw(&block) if already_coerced.include?(@object.class)
74
+ already_coerced << @object.class
75
+ @object =
76
+ case (obj = coecings[@object.class])
77
+ when Symbol ; @object.send obj
78
+ when Proc ; obj.call(@object)
79
+ else ; obj
80
+ end
81
+ retry
82
+ end
83
+
84
+ alias :match :one_of
85
+ end
86
+ end
data/lib/must.rb ADDED
@@ -0,0 +1,12 @@
1
+ # Must
2
+ module Must
3
+ class Invalid < StandardError; end
4
+ class ShouldNotEmpty < Invalid; end
5
+
6
+ def must
7
+ Rule.new(self)
8
+ end
9
+ end
10
+
11
+ require File.dirname(__FILE__) + '/must/rule'
12
+ Object.__send__ :include, Must
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: must
3
+ version: !ruby/object:Gem::Version
4
+ hash: 21
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 2
9
+ - 1
10
+ version: 0.2.1
11
+ platform: ruby
12
+ authors:
13
+ - maiha
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-06-07 00:00:00 +09:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: constraint plugin
23
+ email: maiha@wota.jp
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files:
29
+ - README
30
+ files:
31
+ - README
32
+ - Rakefile
33
+ - lib/must/rule.rb
34
+ - lib/must.rb
35
+ has_rdoc: true
36
+ homepage: http://github.com/maiha/must
37
+ licenses: []
38
+
39
+ post_install_message:
40
+ rdoc_options: []
41
+
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ hash: 3
50
+ segments:
51
+ - 0
52
+ version: "0"
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ requirements: []
63
+
64
+ rubyforge_project: asakusarb
65
+ rubygems_version: 1.3.7
66
+ signing_key:
67
+ specification_version: 3
68
+ summary: constraint plugin
69
+ test_files: []
70
+