fluent_conditions 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,150 @@
1
+ module FluentConditions
2
+
3
+ def self.included(base)
4
+ base.instance_variable_set(:@builder, Class.new(Builder))
5
+
6
+ base.class_eval do
7
+ include InstanceMethods
8
+ end
9
+
10
+ base.extend ClassMethods
11
+ end
12
+
13
+ module InstanceMethods
14
+ def is
15
+ self.class.instance_variable_get(:@builder).new(self, :positive)
16
+ end
17
+
18
+ def is_not
19
+ self.class.instance_variable_get(:@builder).new(self, :negative)
20
+ end
21
+ end
22
+
23
+ module ClassMethods
24
+ def fluent(field, options = {})
25
+ builder = instance_variable_get(:@builder)
26
+
27
+ if options.include?(:values)
28
+ options[:values].each do |value|
29
+ builder.class_eval do
30
+ define_method(value) do
31
+ update_and_continue(instance_variable_get(:@object).send(field) == value)
32
+ end
33
+
34
+ define_method("#{value}?") do
35
+ update_and_finish(instance_variable_get(:@object).send(field) == value)
36
+ end
37
+
38
+ define_method("not_#{value}") do
39
+ update_and_continue(instance_variable_get(:@object).send(field) != value)
40
+ end
41
+
42
+ define_method("not_#{value}?") do
43
+ update_and_finish(instance_variable_get(:@object).send(field) != value)
44
+ end
45
+ end
46
+ end
47
+ elsif options.include?(:if)
48
+ field_name = options[:as]
49
+ condition_check = options[:if]
50
+
51
+ builder.class_eval do
52
+ define_method(field_name) do
53
+ update_and_continue(condition_check.call(instance_variable_get(:@object).send(field)))
54
+ end
55
+
56
+ define_method("#{field_name}?") do
57
+ update_and_finish(condition_check.call(instance_variable_get(:@object).send(field)))
58
+ end
59
+
60
+ define_method("not_#{field_name}") do
61
+ update_and_continue(!condition_check.call(instance_variable_get(:@object).send(field)))
62
+ end
63
+
64
+ define_method("not_#{field_name}?") do
65
+ update_and_finish(!condition_check.call(instance_variable_get(:@object).send(field)))
66
+ end
67
+ end
68
+ else
69
+ builder.class_eval do
70
+ define_method(field) do
71
+ update_and_continue(instance_variable_get(:@object).send(field))
72
+ end
73
+
74
+ define_method("#{field}?") do
75
+ update_and_finish(instance_variable_get(:@object).send(field))
76
+ end
77
+
78
+ define_method("not_#{field}") do
79
+ update_and_continue(!instance_variable_get(:@object).send(field))
80
+ end
81
+
82
+ define_method("not_#{field}?") do
83
+ update_and_finish(!instance_variable_get(:@object).send(field))
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+
91
+ class Builder
92
+ def initialize(object, type)
93
+ @object = object
94
+ @type = type
95
+ @previous, @current, @big_or = true, true, false
96
+ end
97
+
98
+ def or
99
+ @or_flag = true
100
+ self
101
+ end
102
+
103
+ def OR
104
+ @big_or = @big_or || result
105
+ @big_or_flag = true
106
+ @previous, @current = true, true
107
+ self
108
+ end
109
+
110
+ def and
111
+ self
112
+ end
113
+
114
+ private
115
+
116
+ def update_and_continue(field_value)
117
+ update_result(field_value)
118
+ self
119
+ end
120
+
121
+ def update_and_finish(field_value)
122
+ update_result(field_value)
123
+ end_result
124
+ end
125
+
126
+ def update_result(field_value)
127
+ if @or_flag
128
+ @current = @current || field_value
129
+ @or_flag = false
130
+ else
131
+ @previous, @current = @previous && @current, field_value
132
+ end
133
+ end
134
+
135
+ def end_result
136
+ if @big_or_flag
137
+ return (@big_or || result) if @type == :positive
138
+ return !(@big_or || result) if @type == :negative
139
+ end
140
+ return result if @type == :positive
141
+ return !result if @type == :negative
142
+ end
143
+
144
+ def result
145
+ @previous && @current
146
+ end
147
+
148
+ end
149
+ end
150
+
@@ -0,0 +1,240 @@
1
+ require 'spec_helper'
2
+
3
+ module FluentConditions
4
+
5
+ describe Builder do
6
+
7
+ describe "checking simple boolean conditions" do
8
+ before(:each) do
9
+ clazz = Class.new do
10
+ include FluentConditions
11
+ attr_accessor :admin
12
+ fluent :admin
13
+ end
14
+ @obj = clazz.new
15
+ end
16
+
17
+ it "should respond to added methods" do
18
+ @obj.is.should respond_to(:admin)
19
+ @obj.is.should respond_to(:admin?)
20
+ @obj.is.should respond_to(:not_admin)
21
+ @obj.is.should respond_to(:not_admin?)
22
+ end
23
+
24
+ it "should check for admin user if it's admin or not" do
25
+ @obj.admin = true
26
+ @obj.is.admin?.should be_true
27
+ @obj.is.not_admin?.should be_false
28
+ end
29
+
30
+ it "should check for non admin user if it's admin or not" do
31
+ @obj.admin = false
32
+ @obj.is.admin?.should be_false
33
+ @obj.is.not_admin?.should be_true
34
+ end
35
+
36
+ it "should treat nil as false value" do
37
+ @obj.admin = nil
38
+ @obj.is.admin?.should be_false
39
+ end
40
+
41
+ it "should check negative condition" do
42
+ @obj.admin = false
43
+ @obj.is_not.admin?.should be_true
44
+ end
45
+ end
46
+
47
+ describe "more than one condition" do
48
+ before(:each) do
49
+ clazz = Class.new do
50
+ include FluentConditions
51
+ attr_accessor :good, :bad
52
+ fluent :good
53
+ fluent :bad
54
+ end
55
+ @obj = clazz.new
56
+ end
57
+
58
+ it "should check two true conditions" do
59
+ @obj.good = true
60
+ @obj.bad = true
61
+ @obj.is.good.bad?.should be_true
62
+ end
63
+
64
+ it "should check two true/false conditions" do
65
+ @obj.good = true
66
+ @obj.bad = false
67
+ @obj.is.good.bad?.should be_false
68
+ end
69
+
70
+ it "should check two false conditions" do
71
+ @obj.good = false
72
+ @obj.bad = false
73
+ @obj.is.good.bad?.should be_false
74
+ end
75
+ end
76
+
77
+ describe "with or" do
78
+ before(:each) do
79
+ clazz = Class.new do
80
+ include FluentConditions
81
+ attr_accessor :good, :bad
82
+ fluent :good
83
+ fluent :bad
84
+ end
85
+ @obj = clazz.new
86
+ end
87
+
88
+ it "should check two true conditions" do
89
+ @obj.good = true
90
+ @obj.bad = true
91
+ @obj.is.good.or.bad?.should be_true
92
+ end
93
+
94
+ it "should check two true/false conditions" do
95
+ @obj.good = true
96
+ @obj.bad = false
97
+ @obj.is.good.or.bad?.should be_true
98
+ end
99
+
100
+ it "should check two false conditions" do
101
+ @obj.good = false
102
+ @obj.bad = false
103
+ @obj.is.good.or.bad?.should be_false
104
+ end
105
+ end
106
+
107
+ describe "complex conditions" do
108
+ before(:each) do
109
+ clazz = Class.new do
110
+ include FluentConditions
111
+ attr_accessor :good, :bad, :ugly
112
+ fluent :good
113
+ fluent :bad
114
+ fluent :ugly
115
+ end
116
+ @obj = clazz.new
117
+ end
118
+
119
+ it "should pass them all" do
120
+ @obj.good = true
121
+ @obj.bad = false
122
+ @obj.ugly = true
123
+
124
+ @obj.is.good.bad.ugly?.should be_false
125
+ @obj.is.good.ugly.bad?.should be_false
126
+ @obj.is.good.bad.or.ugly?.should be_true
127
+ @obj.is.good.or.bad.and.ugly?.should be_true
128
+ @obj.is.good.ugly.or.bad?.should be_true
129
+
130
+ @obj.is.bad.good.ugly?.should be_false
131
+ @obj.is.bad.ugly.good?.should be_false
132
+ @obj.is.bad.and.good.or.ugly?.should be_false
133
+ @obj.is.bad.ugly.or.good?.should be_false
134
+ @obj.is.bad.or.good.and.ugly?.should be_true
135
+
136
+ @obj.is.ugly.good.bad?.should be_false
137
+ @obj.is.ugly.bad.good?.should be_false
138
+ @obj.is.ugly.or.good.and.bad?.should be_false
139
+ @obj.is.ugly.good.and.bad?.should be_false
140
+ @obj.is.ugly.good.or.bad?.should be_true
141
+
142
+ @obj.is_not.good.bad.and.ugly?.should be_true
143
+ end
144
+ end
145
+
146
+ describe "when values were defined" do
147
+ before(:each) do
148
+ clazz = Class.new do
149
+ include FluentConditions
150
+ attr_accessor :color
151
+ fluent :color, :values => [:red, :green]
152
+ end
153
+ @product = clazz.new
154
+ end
155
+
156
+ it "should respond to accesor methods" do
157
+ @product.is.should respond_to(:red)
158
+ @product.is.should respond_to(:green)
159
+ @product.is.should respond_to(:not_red)
160
+ @product.is.should respond_to(:not_green)
161
+
162
+ @product.is.should respond_to(:red?)
163
+ @product.is.should respond_to(:green?)
164
+ @product.is.should respond_to(:not_red?)
165
+ @product.is.should respond_to(:not_green?)
166
+ end
167
+
168
+ it "should check condition by value" do
169
+ @product.color = :red
170
+
171
+ @product.is.red?.should be_true
172
+ @product.is.green?.should be_false
173
+ @product.is.red.and.green?.should be_false
174
+ @product.is.red.or.green?.should be_true
175
+
176
+ @product.is.not_red?.should be_false
177
+ @product.is.not_green?.should be_true
178
+ end
179
+ end
180
+
181
+ describe "when condition check defined by user" do
182
+ before(:each) do
183
+ clazz = Class.new do
184
+ include FluentConditions
185
+ attr_accessor :length
186
+ fluent :length, :as => :long, :if => proc { |length| length >= 500 }
187
+ fluent :length, :as => :short, :if => proc { |length| length < 500 }
188
+ end
189
+ @post = clazz.new
190
+ end
191
+
192
+ it "should respond to new methods" do
193
+ @post.is.should respond_to(:long)
194
+ @post.is.should respond_to(:not_long)
195
+ @post.is.should respond_to(:long?)
196
+ @post.is.should respond_to(:not_long?)
197
+
198
+ @post.is.should respond_to(:short)
199
+ @post.is.should respond_to(:not_short)
200
+ @post.is.should respond_to(:short?)
201
+ @post.is.should respond_to(:not_short?)
202
+ end
203
+
204
+ it "should check condition defined by user" do
205
+ @post.length = 600
206
+
207
+ @post.is.long?.should be_true
208
+ @post.is.not_long?.should be_false
209
+ @post.is.short?.should be_false
210
+ @post.is.short.or.long?.should be_true
211
+ end
212
+ end
213
+
214
+ describe "when big OR used" do
215
+ before(:each) do
216
+ clazz = Class.new do
217
+ include FluentConditions
218
+ attr_accessor :name, :color
219
+ fluent :name, :values => [:apple, :grass, :sky]
220
+ fluent :color, :values => [:red, :green, :blue]
221
+ end
222
+ @thing = clazz.new
223
+ end
224
+
225
+ it "should check conditions with OR" do
226
+ @thing.name = :apple
227
+ @thing.color = :red
228
+
229
+ @thing.is.green.grass.OR.red.apple?.should be_true
230
+ @thing.is.red.apple.OR.green.grass?.should be_true
231
+ @thing.is.blue.sky.OR.green.grass?.should be_false
232
+
233
+ @thing.is_not.red.apple.OR.green.grass?.should be_false
234
+ @thing.is_not.red.apple.OR.green.grass?.should be_false
235
+ @thing.is_not.blue.sky.OR.green.grass?.should be_true
236
+ end
237
+ end
238
+ end
239
+
240
+ end
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+
3
+ module FluentConditions
4
+
5
+ describe FluentConditions do
6
+
7
+ describe "when module indluded" do
8
+ before(:each) do
9
+ clazz = Class.new do
10
+ include FluentConditions
11
+ end
12
+ @obj = clazz.new
13
+ end
14
+
15
+ it "should provide 'fluent' method now" do
16
+ @obj.class.should respond_to(:fluent)
17
+ end
18
+
19
+ it "should provide 'is' method now" do
20
+ @obj.should respond_to(:is)
21
+ end
22
+
23
+ it "should return Builder object when calling 'is'" do
24
+ @obj.is.should be_kind_of(Builder)
25
+ end
26
+
27
+ it "should return new builder each time" do
28
+ @obj.is.object_id.should_not == @obj.is.object_id
29
+ end
30
+ end
31
+
32
+ describe "when included to different classes" do
33
+ before(:each) do
34
+ class User
35
+ include FluentConditions
36
+ attr_accessor :admin
37
+ fluent :admin
38
+ end
39
+ @user = User.new
40
+ end
41
+
42
+ describe "not in hierarchy" do
43
+ before(:each) do
44
+ class Color
45
+ include FluentConditions
46
+ attr_accessor :blue
47
+ fluent :blue
48
+ end
49
+ @color = Color.new
50
+ end
51
+
52
+ it "should provide builders of different classes" do
53
+ @user.is.class.should_not == @color.is.class
54
+ end
55
+
56
+ it "should not respond to other's builder accessors" do
57
+ @user.is.should_not respond_to(:blue)
58
+ @color.is.should_not respond_to(:admin)
59
+ end
60
+ end
61
+
62
+ describe "in hierarchy" do
63
+ before(:each) do
64
+ class Employee < User
65
+ include FluentConditions
66
+ attr_accessor :manager
67
+ fluent :manager
68
+ end
69
+ @employee = Employee.new
70
+ end
71
+
72
+ it "should provide builders of different classes" do
73
+ @user.is.class.should_not == @employee.is.class
74
+ end
75
+
76
+ it "should not respond to other's builder accessors" do
77
+ @user.is.should_not respond_to(:manager)
78
+ @employee.is.should_not respond_to(:admin)
79
+ end
80
+ end
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1 @@
1
+ require 'fluent_conditions'
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent_conditions
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - pplcanfly
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-09-18 00:00:00.000000000 +02:00
13
+ default_executable:
14
+ dependencies: []
15
+ description:
16
+ email:
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/fluent_conditions.rb
22
+ - spec/spec_helper.rb
23
+ - spec/fluent_conditions/fluent_conditions_spec.rb
24
+ - spec/fluent_conditions/builder_spec.rb
25
+ has_rdoc: true
26
+ homepage: http://github.com/pplcanfly/fluent_conditions
27
+ licenses: []
28
+ post_install_message:
29
+ rdoc_options: []
30
+ require_paths:
31
+ - lib
32
+ required_ruby_version: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 1.8.7
38
+ required_rubygems_version: !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ requirements: []
45
+ rubyforge_project:
46
+ rubygems_version: 1.6.2
47
+ signing_key:
48
+ specification_version: 3
49
+ summary: Simplifies complex conditions
50
+ test_files: []