fluent_conditions 0.0.2

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.
@@ -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: []