act_with_flags 0.2.0 → 3.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/rake.yml +30 -0
- data/.ruby-gemset +1 -1
- data/.ruby-version +1 -1
- data/.watchr +27 -19
- data/Appraisals +12 -4
- data/Gemfile +7 -4
- data/Gemfile.lock +152 -110
- data/MIT-LICENSE +20 -0
- data/README.md +30 -4
- data/Rakefile +6 -7
- data/TODO +21 -0
- data/act_with_flags.gemspec +20 -21
- data/gemfiles/rails_6.0.gemfile +4 -1
- data/gemfiles/{rails_5.2.gemfile → rails_6.1.gemfile} +3 -1
- data/gemfiles/rails_7.0.gemfile +15 -0
- data/lib/act_with_flags/admin.rb +5 -48
- data/lib/act_with_flags/clear.rb +30 -0
- data/lib/act_with_flags/define.rb +6 -35
- data/lib/act_with_flags/flags.rb +67 -0
- data/lib/act_with_flags/print.rb +21 -27
- data/lib/act_with_flags/utils.rb +25 -13
- data/lib/act_with_flags/version.rb +8 -9
- data/lib/act_with_flags.rb +14 -25
- data/test/any_all_none_test.rb +6 -9
- data/test/benchmark_test.rb +73 -0
- data/test/clear_test.rb +5 -7
- data/test/coding_check_add_test.rb +29 -0
- data/test/coding_coverage_test.rb +19 -0
- data/test/coding_mask2d_test.rb +25 -0
- data/test/coding_null_test.rb +29 -0
- data/test/coding_one_test.rb +26 -0
- data/test/coding_reset_test.rb +18 -0
- data/test/inheritance_any_test.rb +9 -33
- data/test/inheritance_test.rb +7 -10
- data/test/internal/app/assets/config/manifest.js +1 -0
- data/test/internal/app/controllers/orders_controller.rb +1 -3
- data/test/internal/app/models/order.rb +1 -5
- data/test/internal/config/routes.rb +1 -1
- data/test/internal/db/schema.rb +6 -7
- data/test/legacy_test.rb +8 -9
- data/test/mask_test.rb +6 -7
- data/test/null_test.rb +3 -5
- data/test/one_test.rb +7 -9
- data/test/origin_test.rb +7 -26
- data/test/origins_test.rb +57 -0
- data/test/remove_from_test.rb +3 -4
- data/test/test_helper.rb +12 -9
- metadata +25 -57
- data/.rubocop.yml +0 -79
- data/.travis.yml +0 -21
- data/LICENSE +0 -21
- data/test/internal_benchmark_test.rb +0 -52
- data/test/internal_check_add_test.rb +0 -36
- data/test/internal_null_test.rb +0 -29
- data/test/internal_one_test.rb +0 -27
- data/test/reset_test.rb +0 -17
@@ -0,0 +1,15 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "rails", "~> 7.0"
|
6
|
+
|
7
|
+
group :test do
|
8
|
+
gem "observr"
|
9
|
+
gem "rubocop", require: false
|
10
|
+
gem "simplecov", require: false
|
11
|
+
gem "benchmark-ips", require: false
|
12
|
+
gem "ricecream", require: false
|
13
|
+
end
|
14
|
+
|
15
|
+
gemspec path: "../"
|
data/lib/act_with_flags/admin.rb
CHANGED
@@ -1,68 +1,25 @@
|
|
1
|
-
# rubocop:disable all
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
class ActWithFlags::Admin
|
5
|
-
|
6
4
|
attr_reader :model
|
7
|
-
attr_reader :origin
|
8
|
-
attr_reader :delete_mask
|
9
5
|
|
10
6
|
def initialize(model)
|
7
|
+
@locations = {}
|
8
|
+
@clears = {}
|
11
9
|
@model = model
|
12
|
-
@origin = :flags
|
13
|
-
@map = {}
|
14
|
-
@delete_mask = 0
|
15
|
-
@max_position = 512 - 1
|
16
10
|
@boolean_hash = {}
|
17
|
-
[true,
|
18
|
-
[false,
|
11
|
+
[true, "true", 1, "1"].each { |x| @boolean_hash[x] = true }
|
12
|
+
[false, "false", 0, "0"].each { |x| @boolean_hash[x] = false }
|
19
13
|
end
|
20
14
|
|
21
15
|
def reset_model(model)
|
22
16
|
initialize model
|
23
17
|
end
|
24
18
|
|
25
|
-
def names
|
26
|
-
@map.keys.sort
|
27
|
-
end
|
28
|
-
|
29
19
|
def to_boolean(value)
|
30
20
|
res = @boolean_hash[value]
|
31
|
-
return res
|
21
|
+
return res unless res.nil?
|
32
22
|
|
33
23
|
raise "invalid boolean <#{value}>"
|
34
24
|
end
|
35
|
-
|
36
|
-
def origin=(name)
|
37
|
-
raise 'invalid update of origin' unless @map.empty? || (origin == name)
|
38
|
-
@origin = name
|
39
|
-
end
|
40
|
-
|
41
|
-
def position(name)
|
42
|
-
pos = @map[name]
|
43
|
-
return pos if pos
|
44
|
-
|
45
|
-
parent = self.model.superclass.act_with_flags
|
46
|
-
return parent.position(name) if parent
|
47
|
-
|
48
|
-
raise "unknown flag '#{model}##{name}'"
|
49
|
-
end
|
50
|
-
|
51
|
-
def mask(*names)
|
52
|
-
names.inject(0) { |msk, name| msk | ( 1 << position(name) ) }
|
53
|
-
end
|
54
|
-
|
55
|
-
def add(name, pos)
|
56
|
-
values = @map.values
|
57
|
-
pos ||= (0..@max_position).detect { |i| !values.include?(i) }
|
58
|
-
raise "invalid position '#{name} @ #{pos}'" unless pos
|
59
|
-
raise "name in use '#{name} @ #{pos}'" if @map.key?(name)
|
60
|
-
raise "position in use '#{name} @ #{pos}'" if @map.value?(pos)
|
61
|
-
@map[name] = pos
|
62
|
-
end
|
63
|
-
|
64
|
-
def add_to_delete_mask(name)
|
65
|
-
@delete_mask |= mask(name)
|
66
|
-
end
|
67
|
-
|
68
25
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ActWithFlags::Admin
|
4
|
+
attr_reader :clears
|
5
|
+
|
6
|
+
def clear_at_save(*flags)
|
7
|
+
flags.each { |name| add_to_clear_mask(name) }
|
8
|
+
clears.each { |orig, mask|
|
9
|
+
before_save(orig, mask)
|
10
|
+
}
|
11
|
+
@clears = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def add_to_clear_mask(name)
|
17
|
+
_model, orig, _pos = location(name).values
|
18
|
+
mask = @clears[orig] || 0
|
19
|
+
mask |= 1 << position(name)
|
20
|
+
@clears[orig] = mask
|
21
|
+
end
|
22
|
+
|
23
|
+
def before_save(orig, mask)
|
24
|
+
model.class_eval %(
|
25
|
+
before_save do |row|
|
26
|
+
row.#{orig} &= ~#{mask}
|
27
|
+
end
|
28
|
+
), __FILE__, __LINE__ - 4
|
29
|
+
end
|
30
|
+
end
|
@@ -1,16 +1,13 @@
|
|
1
|
-
# rubocop:disable all
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
class ActWithFlags::Admin
|
5
|
-
|
6
|
-
def add_accessors(origin, accessor, mask)
|
7
|
-
#p ["act_with_flags#add_accessors:", model, origin, accessor, mask]
|
4
|
+
def add_accessors(accessor, origin, mask)
|
8
5
|
unless model.method_defined?(:act_with_flags)
|
9
6
|
model.class_eval %(
|
10
7
|
def act_with_flags
|
11
8
|
#{model}.act_with_flags
|
12
9
|
end
|
13
|
-
)
|
10
|
+
), __FILE__, __LINE__ - 4
|
14
11
|
end
|
15
12
|
|
16
13
|
model.class_eval %(
|
@@ -19,7 +16,7 @@ class ActWithFlags::Admin
|
|
19
16
|
end
|
20
17
|
|
21
18
|
def #{accessor}?
|
22
|
-
raise "Uninitialized '#{model}.#{origin}'"
|
19
|
+
raise "Uninitialized '#{model}.#{origin}'" if #{origin}.nil?
|
23
20
|
if #{origin}.is_a?(String)
|
24
21
|
flags = self.#{origin}.to_i
|
25
22
|
!( flags & #{mask} ).zero?
|
@@ -29,9 +26,9 @@ class ActWithFlags::Admin
|
|
29
26
|
end
|
30
27
|
|
31
28
|
def #{accessor}=(value)
|
32
|
-
raise "Uninitialized '#{model}.#{origin}'"
|
29
|
+
raise "Uninitialized '#{model}.#{origin}'" if #{origin}.nil?
|
33
30
|
is_a_string = #{origin}.is_a?(String)
|
34
|
-
flags =
|
31
|
+
flags = self.#{origin}.to_i
|
35
32
|
flags ||= 0
|
36
33
|
|
37
34
|
result = self.act_with_flags.to_boolean(value)
|
@@ -44,36 +41,10 @@ class ActWithFlags::Admin
|
|
44
41
|
|
45
42
|
result
|
46
43
|
end
|
47
|
-
)
|
44
|
+
), __FILE__, __LINE__ - 31
|
48
45
|
end
|
49
46
|
|
50
47
|
def remove_accessor(accessor)
|
51
48
|
my_undef model, accessor, "#{accessor}?", "#{accessor}="
|
52
49
|
end
|
53
|
-
|
54
|
-
def validate_accessor(*names)
|
55
|
-
names.each { |acc|
|
56
|
-
raise "redefining #{acc} rejected" if model.method_defined?(acc)
|
57
|
-
}
|
58
|
-
end
|
59
|
-
|
60
|
-
def my_undef(*names)
|
61
|
-
names.each { |name|
|
62
|
-
model.class_eval %(
|
63
|
-
begin
|
64
|
-
undef #{name}
|
65
|
-
rescue
|
66
|
-
end
|
67
|
-
)
|
68
|
-
}
|
69
|
-
end
|
70
|
-
|
71
|
-
def before_save
|
72
|
-
model.class_eval %(
|
73
|
-
before_save do |row|
|
74
|
-
row.#{origin} &= ~row.class.act_with_flags.delete_mask
|
75
|
-
end
|
76
|
-
)
|
77
|
-
end
|
78
|
-
|
79
50
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ActWithFlags::Admin
|
4
|
+
Location = Struct.new(:model, :origin, :position)
|
5
|
+
|
6
|
+
attr_reader :locations
|
7
|
+
|
8
|
+
def mask(*flags)
|
9
|
+
return 0 if flags.empty?
|
10
|
+
|
11
|
+
res = mask2d(*flags)
|
12
|
+
raise "Mixing origins fails: #{flags}" unless res.length == 1
|
13
|
+
|
14
|
+
res.values.first
|
15
|
+
end
|
16
|
+
|
17
|
+
def mask2d(*flags)
|
18
|
+
res = {}
|
19
|
+
flags.each { |flag|
|
20
|
+
model, orig, pos = location(flag).values
|
21
|
+
idx = "#{model}##{orig}"
|
22
|
+
mask = res[idx] || 0
|
23
|
+
res[idx] = mask | (1 << pos)
|
24
|
+
}
|
25
|
+
res
|
26
|
+
end
|
27
|
+
|
28
|
+
def location(name)
|
29
|
+
location = @locations[name]
|
30
|
+
return location if location
|
31
|
+
|
32
|
+
parent = model.superclass.act_with_flags
|
33
|
+
return parent.location(name) if parent
|
34
|
+
|
35
|
+
raise "unknown flag '#{model}##{name}'"
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def position(name)
|
41
|
+
location(name).position
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_to_locations(flag, location)
|
45
|
+
location = check_position(location)
|
46
|
+
who = "<#{flag}: #{location.origin}@#{location.position}>"
|
47
|
+
raise "name already used #{who}" if @locations.key?(flag)
|
48
|
+
bool = @locations.has_value?(location)
|
49
|
+
raise "position already used #{who}" if bool
|
50
|
+
@locations[flag] = location
|
51
|
+
end
|
52
|
+
|
53
|
+
def check_position(location)
|
54
|
+
model, orig, pos = location.values
|
55
|
+
return location if pos
|
56
|
+
|
57
|
+
max_position = -1
|
58
|
+
@locations.each { |name, location|
|
59
|
+
model2, orig2, pos2 = location.values
|
60
|
+
next unless model == model2 && orig == orig2
|
61
|
+
|
62
|
+
max_position = pos2 if pos2 > max_position
|
63
|
+
}
|
64
|
+
|
65
|
+
Location.new(model, orig, max_position + 1)
|
66
|
+
end
|
67
|
+
end
|
data/lib/act_with_flags/print.rb
CHANGED
@@ -1,44 +1,39 @@
|
|
1
|
-
# rubocop:disable all
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
class ActWithFlags::Admin
|
5
|
-
|
6
4
|
def to_s
|
7
5
|
res = []
|
8
|
-
res << title(
|
9
|
-
res << variables(:
|
6
|
+
res << title("Variables")
|
7
|
+
res << variables(:boolean_hash)
|
10
8
|
res << variables(:delete_mask)
|
11
9
|
|
12
|
-
res <<
|
13
|
-
|
14
|
-
|
15
|
-
res << title('Flags sorted by position')
|
16
|
-
@map.sort.sort_by(&:last).each { |key, pos|
|
17
|
-
res << "#{key} #{position(key)}"
|
10
|
+
res << blk("Flags sorted alfabetically") { |key, loc|
|
11
|
+
"#{key} #{loc}"
|
18
12
|
}
|
19
|
-
|
20
|
-
|
21
|
-
@map.sort.each { |key, pos|
|
22
|
-
res << "#{key} #{sprintf('0x%08X', mask(key))}"
|
23
|
-
}
|
24
|
-
|
25
|
-
res << title('FLAG assignment; sorted alfabetically')
|
26
|
-
@map.sort.each { |key, pos|
|
27
|
-
res << "FLAG_#{key.upcase} = #{sprintf('0x%08X', mask(key))}"
|
13
|
+
res << blk("Flags and mask; sorted alfabetically") { |key, loc|
|
14
|
+
"#{key} #{sprintf("0x%08X", mask(key))}"
|
28
15
|
}
|
29
|
-
|
30
|
-
|
31
|
-
@map.sort.sort_by(&:last).each { |key, pos|
|
32
|
-
res << "FLAG_#{key.upcase} = #{sprintf('0x%08X', mask(key))}"
|
16
|
+
res << blk("FLAG assignment; sorted alfabetically") { |key, loc|
|
17
|
+
"FLAG_#{key.upcase} = #{sprintf("0x%08X", mask(key))}"
|
33
18
|
}
|
34
19
|
|
20
|
+
res << title("@locations")
|
21
|
+
res << @locations
|
35
22
|
res.flatten.join("\n")
|
36
23
|
end
|
37
24
|
|
38
|
-
|
25
|
+
private
|
26
|
+
|
39
27
|
def title(msg)
|
40
|
-
sep =
|
41
|
-
[
|
28
|
+
sep = "#" * 10
|
29
|
+
["", "#{sep} #{msg} #{sep}"]
|
30
|
+
end
|
31
|
+
|
32
|
+
def blk(legend, &block)
|
33
|
+
res = [title(legend)]
|
34
|
+
sorted = @locations.sort
|
35
|
+
sorted.each { |key, loc| res << block.call(key, loc) }
|
36
|
+
res
|
42
37
|
end
|
43
38
|
|
44
39
|
def variables(*names)
|
@@ -47,5 +42,4 @@ class ActWithFlags::Admin
|
|
47
42
|
"#{name} #{value}"
|
48
43
|
}
|
49
44
|
end
|
50
|
-
|
51
45
|
end
|
data/lib/act_with_flags/utils.rb
CHANGED
@@ -1,16 +1,14 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class ActWithFlags::Admin
|
4
|
-
|
5
|
-
def add_accessor(name, pos)
|
6
|
-
#p "** act_with_flags: add_accessor '#{name} @ #{pos}'"
|
4
|
+
def add_flag(name, origin, pos)
|
7
5
|
accessor = name.to_sym
|
8
6
|
validate_accessor accessor, "#{accessor}?", "#{accessor}="
|
9
7
|
|
10
|
-
|
8
|
+
loc = Location.new(model, origin, pos)
|
9
|
+
add_to_locations accessor, loc
|
11
10
|
mask = mask(accessor)
|
12
|
-
origin
|
13
|
-
add_accessors(origin, accessor, mask)
|
11
|
+
add_accessors(accessor, origin, mask)
|
14
12
|
end
|
15
13
|
|
16
14
|
def add_mask_et_all(origin)
|
@@ -33,19 +31,33 @@ class ActWithFlags::Admin
|
|
33
31
|
mask = self.class.act_with_flags.mask(*names)
|
34
32
|
( self.#{origin} & mask ).zero?
|
35
33
|
end
|
36
|
-
)
|
37
|
-
end
|
38
|
-
|
39
|
-
def delete_mask_et_all
|
40
|
-
my_undef :flags_mask, :flags_any?, :flags_all?, :flags_none?
|
34
|
+
), __FILE__, __LINE__ - 19
|
41
35
|
end
|
42
36
|
|
43
37
|
def reset
|
44
|
-
|
38
|
+
names = @locations.keys.sort
|
45
39
|
names.each { |name|
|
46
40
|
remove_accessor name
|
47
41
|
}
|
48
42
|
reset_model model
|
49
43
|
end
|
50
44
|
|
45
|
+
private
|
46
|
+
|
47
|
+
def validate_accessor(*names)
|
48
|
+
names.each { |acc|
|
49
|
+
raise "redefining #{acc} rejected" if model.method_defined?(acc)
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def my_undef(*names)
|
54
|
+
names.each { |name|
|
55
|
+
model.class_eval %(
|
56
|
+
begin
|
57
|
+
undef #{name}
|
58
|
+
rescue
|
59
|
+
end
|
60
|
+
), __FILE__, __LINE__ - 5
|
61
|
+
}
|
62
|
+
end
|
51
63
|
end
|
@@ -1,13 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActWithFlags
|
4
|
-
VERSION =
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
# VERSION = '0.0.1' # 2019-02-24
|
4
|
+
VERSION = "3.0.1" # 2022-08-07
|
5
|
+
# VERSION = "3.0.0" # 2022-07-27
|
6
|
+
# VERSION = "0.2.4" # 2021-06-21
|
7
|
+
# VERSION = "0.2.3" # 2020-07-14
|
8
|
+
# VERSION = "0.2.2" # 2020-04-27
|
9
|
+
# VERSION = "0.2.1" # 2020-03-01
|
10
|
+
# VERSION = "0.2.0" # 2019-10-04
|
11
|
+
# VERSION = "0.1.0" # 2019-04-07
|
13
12
|
end
|
data/lib/act_with_flags.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# rubocop:disable all
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
# Principles:
|
@@ -8,47 +7,37 @@
|
|
8
7
|
# POLS
|
9
8
|
# DEI
|
10
9
|
# TDD considered harmful
|
10
|
+
# TGCB
|
11
11
|
|
12
12
|
class << ActiveRecord::Base
|
13
|
-
|
14
|
-
attr_accessor :act_with_flags
|
13
|
+
attr_reader :act_with_flags
|
15
14
|
|
16
15
|
def add_to_flags(*flags, origin: :flags, **hash)
|
17
|
-
|
18
|
-
|
19
|
-
#p "act_with_flags: hash #{hash.inspect}"
|
20
|
-
|
21
|
-
@act_with_flags ||= ActWithFlags::Admin.new self
|
22
|
-
if origin.is_a?(Integer)
|
23
|
-
hash[:origin] = origin
|
24
|
-
else
|
25
|
-
@act_with_flags.origin = origin
|
26
|
-
@act_with_flags.delete_mask_et_all
|
16
|
+
unless @act_with_flags
|
17
|
+
@act_with_flags ||= ActWithFlags::Admin.new self
|
27
18
|
@act_with_flags.add_mask_et_all origin
|
28
19
|
end
|
29
20
|
|
30
|
-
flags.each { |name|
|
31
|
-
hash.each
|
21
|
+
flags.each { |name| @act_with_flags.add_flag(name, origin, nil) }
|
22
|
+
hash.each { |name, pos| @act_with_flags.add_flag(name, origin, pos) }
|
32
23
|
|
33
24
|
@act_with_flags
|
34
25
|
end
|
35
26
|
|
36
27
|
def remove_from_flags(*flags)
|
37
|
-
#p "remove_from_flags #{flags.inspect}"
|
38
28
|
flags.each { |name| @act_with_flags.remove_accessor(name) }
|
39
29
|
end
|
40
30
|
|
41
31
|
def clear_flags_at_save(*flags)
|
42
|
-
|
43
|
-
flags.each { |name| @act_with_flags.add_to_delete_mask(name) }
|
44
|
-
@act_with_flags.before_save
|
32
|
+
@act_with_flags.clear_at_save(*flags)
|
45
33
|
end
|
46
|
-
|
47
34
|
end
|
48
35
|
|
49
36
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__)))
|
50
|
-
require
|
51
|
-
require
|
52
|
-
require
|
53
|
-
require
|
54
|
-
require
|
37
|
+
require "act_with_flags/version"
|
38
|
+
require "act_with_flags/utils"
|
39
|
+
require "act_with_flags/define"
|
40
|
+
require "act_with_flags/admin"
|
41
|
+
require "act_with_flags/flags"
|
42
|
+
require "act_with_flags/clear"
|
43
|
+
require "act_with_flags/print"
|
data/test/any_all_none_test.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
|
-
|
1
|
+
require "test_helper"
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
describe 'any? all? and none?' do
|
3
|
+
describe "any? all? and none?" do
|
6
4
|
let(:order) { Order.create }
|
7
5
|
|
8
6
|
def setup
|
@@ -10,28 +8,28 @@ describe 'any? all? and none?' do
|
|
10
8
|
Order.add_to_flags a: 1, b: 7, c: 3
|
11
9
|
end
|
12
10
|
|
13
|
-
it
|
11
|
+
it "checks any?" do
|
14
12
|
order.a = true
|
15
13
|
assert order.flags_any?(:a, :b)
|
16
14
|
order.a = false
|
17
15
|
refute order.flags_any?(:a, :b)
|
18
16
|
end
|
19
17
|
|
20
|
-
it
|
18
|
+
it "checks any? #2" do
|
21
19
|
order.b = true
|
22
20
|
assert order.flags_any?(:a, :b)
|
23
21
|
order.b = false
|
24
22
|
refute order.flags_any?(:a, :b)
|
25
23
|
end
|
26
24
|
|
27
|
-
it
|
25
|
+
it "checks all?" do
|
28
26
|
order.a = order.b = true
|
29
27
|
assert order.flags_all?(:a, :b)
|
30
28
|
order.a = false
|
31
29
|
refute order.flags_all?(:a, :b)
|
32
30
|
end
|
33
31
|
|
34
|
-
it
|
32
|
+
it "checks none? #2" do
|
35
33
|
order.a = order.b = true
|
36
34
|
refute order.flags_none?(:a, :b)
|
37
35
|
order.a = false
|
@@ -39,5 +37,4 @@ describe 'any? all? and none?' do
|
|
39
37
|
order.b = false
|
40
38
|
assert order.flags_none?(:a, :b)
|
41
39
|
end
|
42
|
-
|
43
40
|
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# For development purposes; do not waste your tine reading it!
|
2
|
+
# YAGNI
|
3
|
+
|
4
|
+
require "test_helper"
|
5
|
+
require "benchmark"
|
6
|
+
require "benchmark/ips"
|
7
|
+
# ENV["MORE"] = "true"
|
8
|
+
|
9
|
+
describe "Internal timings flag" do
|
10
|
+
let(:order) { Order.create }
|
11
|
+
|
12
|
+
def setup
|
13
|
+
reset_order
|
14
|
+
Order.add_to_flags :blocked
|
15
|
+
end
|
16
|
+
|
17
|
+
it "times ips" do
|
18
|
+
return unless ENV["MORE"]
|
19
|
+
|
20
|
+
Benchmark.ips do |x|
|
21
|
+
x.report("assign true : ") { order.blocked = true }
|
22
|
+
x.report("assign false: ") { order.blocked = false }
|
23
|
+
x.report("assign \"false\": ") { order.blocked = "false" }
|
24
|
+
x.report("x = order.blocked? ") { x = order.blocked? }
|
25
|
+
x.report("x = order.blocked ") { x = order.blocked }
|
26
|
+
|
27
|
+
x.compare!
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "Internal timings mask" do
|
33
|
+
let(:order) { Order.create }
|
34
|
+
let(:admin) { Order.act_with_flags }
|
35
|
+
|
36
|
+
def setup
|
37
|
+
reset_order
|
38
|
+
Order.add_to_flags a: 1, b: 7, c: 3
|
39
|
+
# Order.add_to_flags a: 1, b: 60, c: 3
|
40
|
+
# Order.add_to_flags a: 1, b: 1000, c: 3
|
41
|
+
end
|
42
|
+
|
43
|
+
it "times ips" do
|
44
|
+
return unless ENV["MORE"]
|
45
|
+
|
46
|
+
Benchmark.ips do |x|
|
47
|
+
x.report("mask(:a, :b): ") { admin.mask(:a, :b) }
|
48
|
+
x.report("any?(:a, :b): ") { order.flags_any?(:a, :b) }
|
49
|
+
x.report("all?(:a, :b): ") { order.flags_all?(:a, :b) }
|
50
|
+
x.report("none?(:a, :b): ") { order.flags_none?(:a, :b) }
|
51
|
+
|
52
|
+
x.compare!
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class BenchFoo < Minitest::Benchmark
|
58
|
+
def bench_order_blocked
|
59
|
+
return unless ENV["MORE"]
|
60
|
+
|
61
|
+
n = 1_000_000
|
62
|
+
n = 100_000
|
63
|
+
n = 10_000
|
64
|
+
Order.add_to_flags :blocked2
|
65
|
+
order = Order.create
|
66
|
+
assert_performance_constant do |input|
|
67
|
+
n.times do
|
68
|
+
order.blocked2 = true
|
69
|
+
order.blocked2 = !order.blocked2
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/test/clear_test.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
require
|
1
|
+
require "test_helper"
|
2
2
|
|
3
|
-
describe
|
4
|
-
let(:admin) { Order.act_with_flags }
|
3
|
+
describe "Clear flags at save" do
|
5
4
|
let(:order) { Order.create }
|
6
5
|
|
7
6
|
def setup
|
@@ -10,21 +9,20 @@ describe 'Clear Flags at Save' do
|
|
10
9
|
order.a = order.b = order.c = true
|
11
10
|
end
|
12
11
|
|
13
|
-
it
|
12
|
+
it "checks sanity" do
|
14
13
|
assert_equal 0x8a, order.flags
|
15
14
|
assert order.b
|
16
15
|
end
|
17
16
|
|
18
|
-
it
|
17
|
+
it "clear flags during save" do
|
19
18
|
Order.clear_flags_at_save :b
|
20
19
|
order.save
|
21
20
|
order.reload
|
22
21
|
assert_equal 0x0a, order.flags
|
23
22
|
end
|
24
23
|
|
25
|
-
it
|
24
|
+
it "does not remove accessor" do
|
26
25
|
Order.clear_flags_at_save :b
|
27
26
|
Order.respond_to? :b
|
28
27
|
end
|
29
|
-
|
30
28
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
describe "Internal check add flag" do
|
4
|
+
let(:order) { Order.create }
|
5
|
+
|
6
|
+
def setup
|
7
|
+
reset_order
|
8
|
+
Order.add_to_flags a: 1, b: 7
|
9
|
+
end
|
10
|
+
|
11
|
+
it "skip reserved position" do
|
12
|
+
Order.add_to_flags :xx
|
13
|
+
order.xx = true
|
14
|
+
assert_equal 0x100, order.flags
|
15
|
+
|
16
|
+
Order.add_to_flags :yy
|
17
|
+
order.yy = true
|
18
|
+
assert_equal 0x300, order.flags
|
19
|
+
end
|
20
|
+
|
21
|
+
it "rejects redefinition" do
|
22
|
+
Order.add_to_flags :z
|
23
|
+
assert_raises { Order.add_to_flags :z }
|
24
|
+
end
|
25
|
+
|
26
|
+
it "rejects reuse of position" do
|
27
|
+
assert_raises { Order.add_to_flags qq: 1 }
|
28
|
+
end
|
29
|
+
end
|