act_with_flags 0.2.3 → 3.1.0
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.
- checksums.yaml +4 -4
- data/.github/workflows/rake.yml +30 -0
- data/.ruby-gemset +1 -1
- data/.ruby-version +1 -1
- data/.watchr +29 -16
- data/Appraisals +12 -4
- data/Gemfile +7 -6
- data/Gemfile.lock +156 -125
- data/MIT-LICENSE +1 -1
- data/README.md +77 -10
- data/Rakefile +5 -5
- data/act_with_flags.gemspec +20 -20
- 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 +65 -0
- data/lib/act_with_flags/print.rb +21 -27
- data/lib/act_with_flags/utils.rb +33 -13
- data/lib/act_with_flags/version.rb +9 -13
- data/lib/act_with_flags.rb +28 -33
- 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/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/range_test.rb +89 -0
- data/test/remove_from_test.rb +3 -4
- data/test/test_helper.rb +9 -9
- metadata +47 -67
- data/.rubocop.yml +0 -8
- data/.travis.yml +0 -23
- 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
    
        data/act_with_flags.gemspec
    CHANGED
    
    | @@ -1,28 +1,28 @@ | |
| 1 | 
            -
            lib = File.expand_path( | 
| 1 | 
            +
            lib = File.expand_path("lib", __dir__)
         | 
| 2 2 | 
             
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         | 
| 3 | 
            -
            require  | 
| 3 | 
            +
            require "act_with_flags/version"
         | 
| 4 4 |  | 
| 5 5 | 
             
            Gem::Specification.new do |s|
         | 
| 6 | 
            -
              s.name | 
| 7 | 
            -
              s.version | 
| 8 | 
            -
              s.summary | 
| 9 | 
            -
              s.description = %(Handles flags in a Rails model instance)
         | 
| 10 | 
            -
              s.authors | 
| 11 | 
            -
              s.email | 
| 12 | 
            -
              s.homepage | 
| 6 | 
            +
              s.name = "act_with_flags"
         | 
| 7 | 
            +
              s.version = ActWithFlags::VERSION
         | 
| 8 | 
            +
              s.summary = %(act_with_flags gem)
         | 
| 9 | 
            +
              s.description = %(Handles flags/booleans in a Rails model instance)
         | 
| 10 | 
            +
              s.authors = ["Dittmar Krall"]
         | 
| 11 | 
            +
              s.email = ["dittmar.krall@matiq.com"]
         | 
| 12 | 
            +
              s.homepage = "http://matiq.com"
         | 
| 13 13 |  | 
| 14 | 
            -
              s.license | 
| 15 | 
            -
              s.platform | 
| 14 | 
            +
              s.license = "MIT"
         | 
| 15 | 
            +
              s.platform = Gem::Platform::RUBY
         | 
| 16 | 
            +
              s.metadata["source_code_uri"] = "https://github.com/matique/act_with_flags"
         | 
| 16 17 |  | 
| 17 | 
            -
              s.files | 
| 18 | 
            -
              s. | 
| 19 | 
            -
              s.require_paths = ['lib']
         | 
| 18 | 
            +
              s.files = `git ls-files -z`.split("\x0")
         | 
| 19 | 
            +
              s.require_paths = ["lib"]
         | 
| 20 20 |  | 
| 21 | 
            -
              s.add_development_dependency  | 
| 22 | 
            -
              s.add_development_dependency  | 
| 23 | 
            -
              s.add_development_dependency  | 
| 24 | 
            -
              s.add_development_dependency  | 
| 21 | 
            +
              s.add_development_dependency "bundler"
         | 
| 22 | 
            +
              s.add_development_dependency "rake"
         | 
| 23 | 
            +
              s.add_development_dependency "appraisal"
         | 
| 24 | 
            +
              s.add_development_dependency "combustion"
         | 
| 25 25 |  | 
| 26 | 
            -
              s.add_development_dependency  | 
| 27 | 
            -
              s.add_development_dependency  | 
| 26 | 
            +
              s.add_development_dependency "minitest"
         | 
| 27 | 
            +
              s.add_development_dependency "sqlite3"
         | 
| 28 28 | 
             
            end
         | 
    
        data/gemfiles/rails_6.0.gemfile
    CHANGED
    
    
| @@ -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,65 @@ | |
| 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 | 
            +
                who = "<#{flag}: #{location.origin}@#{location.position}>"
         | 
| 46 | 
            +
                raise "name already used #{who}" if @locations.key?(flag)
         | 
| 47 | 
            +
                bool = @locations.has_value?(location)
         | 
| 48 | 
            +
                raise "position already used #{who}" if bool
         | 
| 49 | 
            +
                @locations[flag] = location
         | 
| 50 | 
            +
              end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
              def check_pos(model, origin, pos)
         | 
| 53 | 
            +
                return pos if pos
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                max_position = -1
         | 
| 56 | 
            +
                @locations.each { |name, location|
         | 
| 57 | 
            +
                  model2, orig2, pos2 = location.values
         | 
| 58 | 
            +
                  next unless model == model2 && origin == orig2
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  max_position = pos2 if pos2 > max_position
         | 
| 61 | 
            +
                }
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                max_position + 1
         | 
| 64 | 
            +
              end
         | 
| 65 | 
            +
            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,22 @@ | |
| 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, pos, origin, range)
         | 
| 7 5 | 
             
                accessor = name.to_sym
         | 
| 8 6 | 
             
                validate_accessor accessor, "#{accessor}?", "#{accessor}="
         | 
| 9 7 |  | 
| 10 | 
            -
                 | 
| 8 | 
            +
                pos = check_pos(model, origin, pos)
         | 
| 9 | 
            +
                loc = Location.new(model, origin, pos)
         | 
| 10 | 
            +
                add_to_locations accessor, loc
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                unless range.nil?
         | 
| 13 | 
            +
                  unless range.cover?(pos)
         | 
| 14 | 
            +
                    raise RangeError, "Position <#{loc.position}> out of range <#{range}>"
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 11 18 | 
             
                mask = mask(accessor)
         | 
| 12 | 
            -
                origin  | 
| 13 | 
            -
                add_accessors(origin, accessor, mask)
         | 
| 19 | 
            +
                add_accessors(accessor, origin, mask)
         | 
| 14 20 | 
             
              end
         | 
| 15 21 |  | 
| 16 22 | 
             
              def add_mask_et_all(origin)
         | 
| @@ -33,19 +39,33 @@ class ActWithFlags::Admin | |
| 33 39 | 
             
                    mask = self.class.act_with_flags.mask(*names)
         | 
| 34 40 | 
             
                    ( self.#{origin} & mask ).zero?
         | 
| 35 41 | 
             
                  end
         | 
| 36 | 
            -
                )
         | 
| 37 | 
            -
              end
         | 
| 38 | 
            -
             | 
| 39 | 
            -
              def delete_mask_et_all
         | 
| 40 | 
            -
                my_undef :flags_mask, :flags_any?, :flags_all?, :flags_none?
         | 
| 42 | 
            +
                ), __FILE__, __LINE__ - 19
         | 
| 41 43 | 
             
              end
         | 
| 42 44 |  | 
| 43 45 | 
             
              def reset
         | 
| 44 | 
            -
                 | 
| 46 | 
            +
                names = @locations.keys.sort
         | 
| 45 47 | 
             
                names.each { |name|
         | 
| 46 48 | 
             
                  remove_accessor name
         | 
| 47 49 | 
             
                }
         | 
| 48 50 | 
             
                reset_model model
         | 
| 49 51 | 
             
              end
         | 
| 50 52 |  | 
| 53 | 
            +
              private
         | 
| 54 | 
            +
             | 
| 55 | 
            +
              def validate_accessor(*names)
         | 
| 56 | 
            +
                names.each { |acc|
         | 
| 57 | 
            +
                  raise "redefining #{acc} rejected" if model.method_defined?(acc)
         | 
| 58 | 
            +
                }
         | 
| 59 | 
            +
              end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
              def my_undef(*names)
         | 
| 62 | 
            +
                names.each { |name|
         | 
| 63 | 
            +
                  model.class_eval %(
         | 
| 64 | 
            +
                    begin
         | 
| 65 | 
            +
                      undef #{name}
         | 
| 66 | 
            +
                    rescue
         | 
| 67 | 
            +
                    end
         | 
| 68 | 
            +
                  ), __FILE__, __LINE__ - 5
         | 
| 69 | 
            +
                }
         | 
| 70 | 
            +
              end
         | 
| 51 71 | 
             
            end
         | 
| @@ -1,17 +1,13 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 | 
            -
            # rubocop: disable all
         | 
| 3 2 |  | 
| 4 3 | 
             
            module ActWithFlags
         | 
| 5 | 
            -
              VERSION =  | 
| 6 | 
            -
            # VERSION =  | 
| 7 | 
            -
            # VERSION =  | 
| 8 | 
            -
            # VERSION =  | 
| 9 | 
            -
            # VERSION =  | 
| 10 | 
            -
            # VERSION =  | 
| 11 | 
            -
            # VERSION =  | 
| 12 | 
            -
            # VERSION =  | 
| 13 | 
            -
            # VERSION =  | 
| 14 | 
            -
            # VERSION = '0.0.3'     # 2019-03-01
         | 
| 15 | 
            -
            # VERSION = '0.0.2'     # 2019-02-28
         | 
| 16 | 
            -
            # VERSION = '0.0.1'     # 2019-02-24
         | 
| 4 | 
            +
              VERSION = "3.1.0" # 2022-08-29
         | 
| 5 | 
            +
              # VERSION = "3.0.1" # 2022-08-07
         | 
| 6 | 
            +
              # VERSION = "3.0.0" # 2022-07-27
         | 
| 7 | 
            +
              # VERSION = "0.2.4" # 2021-06-21
         | 
| 8 | 
            +
              # VERSION = "0.2.3" # 2020-07-14
         | 
| 9 | 
            +
              # VERSION = "0.2.2" # 2020-04-27
         | 
| 10 | 
            +
              # VERSION = "0.2.1" # 2020-03-01
         | 
| 11 | 
            +
              # VERSION = "0.2.0" # 2019-10-04
         | 
| 12 | 
            +
              # VERSION = "0.1.0" # 2019-04-07
         | 
| 17 13 | 
             
            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,43 @@ | |
| 8 7 | 
             
            #  POLS
         | 
| 9 8 | 
             
            #  DEI
         | 
| 10 9 | 
             
            #  TDD considered harmful
         | 
| 10 | 
            +
            #  TGCB
         | 
| 11 11 |  | 
| 12 | 
            -
             | 
| 12 | 
            +
            module ActWithFlags
         | 
| 13 | 
            +
              module Base
         | 
| 14 | 
            +
                attr_reader :act_with_flags
         | 
| 13 15 |  | 
| 14 | 
            -
             | 
| 16 | 
            +
                def add_to_flags(*flags, origin: :flags, range: nil, **hash)
         | 
| 17 | 
            +
                  unless @act_with_flags
         | 
| 18 | 
            +
                    @act_with_flags ||= ActWithFlags::Admin.new self
         | 
| 19 | 
            +
                    @act_with_flags.add_mask_et_all origin
         | 
| 20 | 
            +
                  end
         | 
| 15 21 |  | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
            #p "act_with_flags: origin #{origin.inspect}"
         | 
| 19 | 
            -
            #p "act_with_flags: hash   #{hash.inspect}"
         | 
| 22 | 
            +
                  flags.each { |name| @act_with_flags.add_flag(name, nil, origin, range) }
         | 
| 23 | 
            +
                  hash.each { |name, pos| @act_with_flags.add_flag(name, pos, origin, range) }
         | 
| 20 24 |  | 
| 21 | 
            -
             | 
| 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
         | 
| 27 | 
            -
                  @act_with_flags.add_mask_et_all origin
         | 
| 25 | 
            +
                  @act_with_flags
         | 
| 28 26 | 
             
                end
         | 
| 29 27 |  | 
| 30 | 
            -
                 | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
                @act_with_flags
         | 
| 34 | 
            -
              end
         | 
| 35 | 
            -
             | 
| 36 | 
            -
              def remove_from_flags(*flags)
         | 
| 37 | 
            -
            #p "remove_from_flags #{flags.inspect}"
         | 
| 38 | 
            -
                flags.each { |name| @act_with_flags.remove_accessor(name) }
         | 
| 39 | 
            -
              end
         | 
| 28 | 
            +
                def remove_from_flags(*flags)
         | 
| 29 | 
            +
                  flags.each { |name| @act_with_flags.remove_accessor(name) }
         | 
| 30 | 
            +
                end
         | 
| 40 31 |  | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
                 | 
| 44 | 
            -
                @act_with_flags.before_save
         | 
| 32 | 
            +
                def clear_flags_at_save(*flags)
         | 
| 33 | 
            +
                  @act_with_flags.clear_at_save(*flags)
         | 
| 34 | 
            +
                end
         | 
| 45 35 | 
             
              end
         | 
| 36 | 
            +
            end
         | 
| 46 37 |  | 
| 38 | 
            +
            class ActiveRecord::Base
         | 
| 39 | 
            +
              extend ActWithFlags::Base
         | 
| 47 40 | 
             
            end
         | 
| 48 41 |  | 
| 49 42 | 
             
            $LOAD_PATH.unshift(File.join(File.dirname(__FILE__)))
         | 
| 50 | 
            -
            require  | 
| 51 | 
            -
            require  | 
| 52 | 
            -
            require  | 
| 53 | 
            -
            require  | 
| 54 | 
            -
            require  | 
| 43 | 
            +
            require "act_with_flags/version"
         | 
| 44 | 
            +
            require "act_with_flags/utils"
         | 
| 45 | 
            +
            require "act_with_flags/define"
         | 
| 46 | 
            +
            require "act_with_flags/admin"
         | 
| 47 | 
            +
            require "act_with_flags/flags"
         | 
| 48 | 
            +
            require "act_with_flags/clear"
         | 
| 49 | 
            +
            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
         |