must 0.2.1

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