togglefy 1.1.0 → 1.2.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/README.md +73 -9
 - data/Rakefile +12 -0
 - data/app/models/togglefy/feature.rb +7 -5
 - data/app/models/togglefy/feature_assignment.rb +3 -1
 - data/lib/generators/togglefy/install_generator.rb +3 -1
 - data/lib/generators/togglefy/templates/create_feature_assignments.rb +8 -3
 - data/lib/generators/togglefy/templates/create_features.rb +5 -1
 - data/lib/togglefy/assignable.rb +13 -10
 - data/lib/togglefy/engine.rb +3 -1
 - data/lib/togglefy/errors/assignables_not_found.rb +3 -1
 - data/lib/togglefy/errors/bulk_toggle_failed.rb +3 -1
 - data/lib/togglefy/errors/dependency_missing.rb +3 -1
 - data/lib/togglefy/errors/error.rb +3 -1
 - data/lib/togglefy/errors/feature_not_found.rb +3 -1
 - data/lib/togglefy/errors/invalid_feature_attribute.rb +3 -1
 - data/lib/togglefy/exceptions.rb +3 -1
 - data/lib/togglefy/feature_assignable_manager.rb +2 -0
 - data/lib/togglefy/feature_manager.rb +3 -1
 - data/lib/togglefy/feature_query.rb +20 -8
 - data/lib/togglefy/featureable.rb +3 -1
 - data/lib/togglefy/scoped_bulk_wrapper.rb +3 -1
 - data/lib/togglefy/services/bulk_toggler.rb +67 -66
 - data/lib/togglefy/version.rb +1 -1
 - data/lib/togglefy.rb +13 -13
 - data/togglefy.gemspec +10 -4
 - metadata +74 -3
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: a5938d2ca0587fdf06293a3e2da8ad72bb6b7c642eab6a6f12d80f51d963bc3d
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: eab43dc22d9a8d0be5566fe2ac81c710d95a6e42972a46073e2e8e390262d894
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 62cfb19a3d90fa016d451f5fa784a5ce549f8500e43bbd75eb59fa184c3dfb999f65c82eedc41b543830772a7a116287f8a8521b04c775d9f1cea93e66938b99
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: cdafbc45941cb93063cad62a4491fd87dc4714da4f71949b686bec1a850246a0d50a0680a4dbd5644c59f001924e01d917bc499a06063c753327121b00a94e26
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -12,7 +12,7 @@ Togglefy is free, open source and you are welcome to help build it. 
     | 
|
| 
       12 
12 
     | 
    
         
             
            Add the gem manually to your Gemfile:
         
     | 
| 
       13 
13 
     | 
    
         | 
| 
       14 
14 
     | 
    
         
             
            ```gemfile
         
     | 
| 
       15 
     | 
    
         
            -
            gem 'togglefy', '~> 1.0', '>= 1.1. 
     | 
| 
      
 15 
     | 
    
         
            +
            gem 'togglefy', '~> 1.0', '>= 1.1.1'
         
     | 
| 
       16 
16 
     | 
    
         
             
            ```
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
18 
     | 
    
         
             
            Or install it and add to the application's Gemfile by executing:
         
     | 
| 
         @@ -37,7 +37,37 @@ After adding the gem to your project, you need to run the generate command to ad 
     | 
|
| 
       37 
37 
     | 
    
         
             
            rails generate togglefy:install
         
     | 
| 
       38 
38 
     | 
    
         
             
            ```
         
     | 
| 
       39 
39 
     | 
    
         | 
| 
       40 
     | 
    
         
            -
            This command will create the migrations to create the tables inside your project. 
     | 
| 
      
 40 
     | 
    
         
            +
            This command will create the migrations to create the tables inside your project.
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            If you use an older version of Rails (< 5), then the migration files don't need you to specify the version.
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            To fix this, you will have to manually go to the two migration files of Togglefy: `create_feature` and `create_feature_assignments` and do the following:
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            Change these lines from this:
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 49 
     | 
    
         
            +
            rails_version = "#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}"
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
            class CreateTogglefyFeatures < ActiveRecord::Migration[rails_version]
         
     | 
| 
      
 52 
     | 
    
         
            +
            ```
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 55 
     | 
    
         
            +
            rails_version = "#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}"
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
            class CreateTogglefyFeatureAssignments < ActiveRecord::Migration[rails_version]
         
     | 
| 
      
 58 
     | 
    
         
            +
            ```
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
            To this:
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 63 
     | 
    
         
            +
            class CreateTogglefyFeatures < ActiveRecord::Migration
         
     | 
| 
      
 64 
     | 
    
         
            +
            ```
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 67 
     | 
    
         
            +
            class CreateTogglefyFeatureAssignments < ActiveRecord::Migration
         
     | 
| 
      
 68 
     | 
    
         
            +
            ```
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
            Please, don't remove/change anything else that's there or Togglefy may not work as expected.
         
     | 
| 
       41 
71 
     | 
    
         | 
| 
       42 
72 
     | 
    
         
             
            Run the migration to create these in your datase:
         
     | 
| 
       43 
73 
     | 
    
         
             
            ```bash
         
     | 
| 
         @@ -428,8 +458,8 @@ You can use either, as long as you respect the rules listed. 
     | 
|
| 
       428 
458 
     | 
    
         
             
            | `without_group`       | `without_role`       | Can't be used if doing a direct `Togglefy::Feature` |
         
     | 
| 
       429 
459 
     | 
    
         
             
            | `for_environment`     | `for_env`            | Can't be used if doing a direct `Togglefy::Feature` |
         
     | 
| 
       430 
460 
     | 
    
         
             
            | `without_environment` | `without_env`        | Can't be used if doing a direct `Togglefy::Feature` |
         
     | 
| 
       431 
     | 
    
         
            -
            | `group` 
     | 
| 
       432 
     | 
    
         
            -
            | `environment`         | `env`                | Used inside methods that receives filters 
     | 
| 
      
 461 
     | 
    
         
            +
            | `group`               | `role`               | Used inside methods that receives filters           |
         
     | 
| 
      
 462 
     | 
    
         
            +
            | `environment`         | `env`                | Used inside methods that receives filters           |
         
     | 
| 
       433 
463 
     | 
    
         
             
            | `create`              | `create_feature`     | None                                                |
         
     | 
| 
       434 
464 
     | 
    
         
             
            | `update`              | `update_feature`     | None                                                |
         
     | 
| 
       435 
465 
     | 
    
         
             
            | `toggle`              | `toggle_feature`     | None                                                |
         
     | 
| 
         @@ -439,16 +469,50 @@ You can use either, as long as you respect the rules listed. 
     | 
|
| 
       439 
469 
     | 
    
         | 
| 
       440 
470 
     | 
    
         | 
| 
       441 
471 
     | 
    
         
             
            ## Development
         
     | 
| 
       442 
     | 
    
         
            -
             
     | 
| 
       443 
     | 
    
         
            -
             
     | 
| 
       444 
     | 
    
         
            -
             
     | 
| 
       445 
     | 
    
         
            -
             
     | 
| 
      
 472 
     | 
    
         
            +
            ### Setup the environment
         
     | 
| 
      
 473 
     | 
    
         
            +
            1. Clone the repository
         
     | 
| 
      
 474 
     | 
    
         
            +
            2. Run `bin/setup` on the Gem's root directory to install dependencies and run the dummy Rails app migrations used for tests
         
     | 
| 
      
 475 
     | 
    
         
            +
            3. Create your branch and checkout to it
         
     | 
| 
      
 476 
     | 
    
         
            +
             
     | 
| 
      
 477 
     | 
    
         
            +
            ### Running the tests
         
     | 
| 
      
 478 
     | 
    
         
            +
            1. Make sure that the dummy Rails app db and migrations were ran
         
     | 
| 
      
 479 
     | 
    
         
            +
            2. Run `bundle exec rspec` on the Gem's root directory to run all the tests
         
     | 
| 
      
 480 
     | 
    
         
            +
            3. If you want to specify a single file to run the tests: `bundle exec rspec path/to/spec/file.rb`
         
     | 
| 
      
 481 
     | 
    
         
            +
            4. If you want to specify a single test of a single file to run: `bundle exec spec path/to/spec/file.rb:42` where 42 represents the number of the line
         
     | 
| 
      
 482 
     | 
    
         
            +
             
     | 
| 
      
 483 
     | 
    
         
            +
            ### Running RuboCop
         
     | 
| 
      
 484 
     | 
    
         
            +
            1. Make sure you're at the Gem's root directory
         
     | 
| 
      
 485 
     | 
    
         
            +
            2. Run `bundle exec rubocop` to run RuboCop on all files not ignored by the `.rubocop.yml` file
         
     | 
| 
      
 486 
     | 
    
         
            +
            3. Run `bundle exec rubocop app spec lib/something.rb` to run RuboCop on specific directories/files
         
     | 
| 
      
 487 
     | 
    
         
            +
            4. Run `bundle exec rubocop -a` to fix all the auto-correctable offenses listed by RuboCop
         
     | 
| 
      
 488 
     | 
    
         
            +
             
     | 
| 
      
 489 
     | 
    
         
            +
            ### Other
         
     | 
| 
      
 490 
     | 
    
         
            +
            1. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
         
     | 
| 
      
 491 
     | 
    
         
            +
             
     | 
| 
      
 492 
     | 
    
         
            +
            ### Use local Togglefy Gem with a Rails application
         
     | 
| 
      
 493 
     | 
    
         
            +
            1. Open the Gemfile of your Rails application
         
     | 
| 
      
 494 
     | 
    
         
            +
            2. Add the following: `gem "togglefy", path: "path/to/togglefy/directory"`
         
     | 
| 
      
 495 
     | 
    
         
            +
            3. Now you can test everything inside of your Rails application
         
     | 
| 
      
 496 
     | 
    
         
            +
             
     | 
| 
      
 497 
     | 
    
         
            +
            #### If you make a change to the Togglefy's code and want to test it, make sure to:
         
     | 
| 
      
 498 
     | 
    
         
            +
            1. If you're running a Rails server: restart
         
     | 
| 
      
 499 
     | 
    
         
            +
            2. If you're running a Rails console: `reload!` or restart
         
     | 
| 
       446 
500 
     | 
    
         | 
| 
       447 
501 
     | 
    
         
             
            ## Contributing
         
     | 
| 
       448 
502 
     | 
    
         | 
| 
       449 
503 
     | 
    
         
             
            Bug reports and pull requests are welcome on GitHub at https://github.com/azeveco/togglefy. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/azeveco/togglefy/blob/master/CODE_OF_CONDUCT.md).
         
     | 
| 
       450 
504 
     | 
    
         | 
| 
       451 
     | 
    
         
            -
             
     | 
| 
      
 505 
     | 
    
         
            +
            * Where can I check for planned features but not started?
         
     | 
| 
      
 506 
     | 
    
         
            +
              * You can check Togglefy's project here: https://github.com/users/azeveco/projects/2 to see the priorities, status and more
         
     | 
| 
      
 507 
     | 
    
         
            +
              * Or you can check the issues: https://github.com/azeveco/Togglefy/issues
         
     | 
| 
      
 508 
     | 
    
         
            +
            * I have an idea of a feature! What do I do?
         
     | 
| 
      
 509 
     | 
    
         
            +
              * First things first, check if there's an issue about it first. If it does, put your comments there. If it doesn't, do the following:
         
     | 
| 
      
 510 
     | 
    
         
            +
                * Are you a developer that wants to develop it? Create a new issue, select the New Feature 🚀 template and fill out everything
         
     | 
| 
      
 511 
     | 
    
         
            +
                * Are you a developer or just an user that would like to request a new feature? Create a new issue, select the Feature Request 💡 template and fill out everything
         
     | 
| 
      
 512 
     | 
    
         
            +
            * I have a bug report. Where can I... report it?
         
     | 
| 
      
 513 
     | 
    
         
            +
              * Create an issue, select the Bug Report 🪲 template and fill out everything
         
     | 
| 
      
 514 
     | 
    
         
            +
             
     | 
| 
      
 515 
     | 
    
         
            +
            There's a PR and Issues Templates. We recommend you to follow these strictly to help everyone.
         
     | 
| 
       452 
516 
     | 
    
         | 
| 
       453 
517 
     | 
    
         
             
            ## License
         
     | 
| 
       454 
518 
     | 
    
         | 
    
        data/Rakefile
    ADDED
    
    
| 
         @@ -1,11 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module Togglefy
         
     | 
| 
       2 
4 
     | 
    
         
             
              class Feature < ApplicationRecord
         
     | 
| 
       3 
     | 
    
         
            -
                enum :status, [ 
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
      
 5 
     | 
    
         
            +
                enum :status, %i[inactive active]
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
       5 
7 
     | 
    
         
             
                has_many :feature_assignments, dependent: :destroy
         
     | 
| 
       6 
8 
     | 
    
         
             
                has_many :assignables, through: :feature_assignments, source: :assignable
         
     | 
| 
       7 
9 
     | 
    
         | 
| 
       8 
     | 
    
         
            -
                before_validation :build_identifier
         
     | 
| 
      
 10 
     | 
    
         
            +
                before_validation :build_identifier, if: proc { |f| f.name.present? && f.identifier.blank? }
         
     | 
| 
       9 
11 
     | 
    
         | 
| 
       10 
12 
     | 
    
         
             
                scope :identifier, ->(identifier) { where(identifier:) }
         
     | 
| 
       11 
13 
     | 
    
         | 
| 
         @@ -27,7 +29,7 @@ module Togglefy 
     | 
|
| 
       27 
29 
     | 
    
         
             
                private
         
     | 
| 
       28 
30 
     | 
    
         | 
| 
       29 
31 
     | 
    
         
             
                def build_identifier
         
     | 
| 
       30 
     | 
    
         
            -
                  self.identifier =  
     | 
| 
      
 32 
     | 
    
         
            +
                  self.identifier = name.underscore.parameterize(separator: "_")
         
     | 
| 
       31 
33 
     | 
    
         
             
                end
         
     | 
| 
       32 
34 
     | 
    
         
             
              end
         
     | 
| 
       33 
     | 
    
         
            -
            end
         
     | 
| 
      
 35 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,3 +1,5 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module Togglefy
         
     | 
| 
       2 
4 
     | 
    
         
             
              class FeatureAssignment < ApplicationRecord
         
     | 
| 
       3 
5 
     | 
    
         
             
                belongs_to :feature, class_name: "Togglefy::Feature"
         
     | 
| 
         @@ -5,4 +7,4 @@ module Togglefy 
     | 
|
| 
       5 
7 
     | 
    
         | 
| 
       6 
8 
     | 
    
         
             
                scope :for_type, ->(klass) { where(assignable_type: klass.to_s) }
         
     | 
| 
       7 
9 
     | 
    
         
             
              end
         
     | 
| 
       8 
     | 
    
         
            -
            end
         
     | 
| 
      
 10 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,3 +1,5 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            require "rails/generators"
         
     | 
| 
       2 
4 
     | 
    
         
             
            require "rails/generators/migration"
         
     | 
| 
       3 
5 
     | 
    
         | 
| 
         @@ -8,7 +10,7 @@ module Togglefy 
     | 
|
| 
       8 
10 
     | 
    
         | 
| 
       9 
11 
     | 
    
         
             
                  source_root File.expand_path("templates", __dir__)
         
     | 
| 
       10 
12 
     | 
    
         | 
| 
       11 
     | 
    
         
            -
                  def self.next_migration_number( 
     | 
| 
      
 13 
     | 
    
         
            +
                  def self.next_migration_number(_path)
         
     | 
| 
       12 
14 
     | 
    
         
             
                    Time.now.utc.strftime("%Y%m%d%H%M%S")
         
     | 
| 
       13 
15 
     | 
    
         
             
                  end
         
     | 
| 
       14 
16 
     | 
    
         | 
| 
         @@ -1,10 +1,15 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
             
     | 
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            rails_version = "#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            class CreateTogglefyFeatureAssignments < ActiveRecord::Migration[rails_version]
         
     | 
| 
       2 
6 
     | 
    
         
             
              def change
         
     | 
| 
       3 
7 
     | 
    
         
             
                create_table :togglefy_feature_assignments do |t|
         
     | 
| 
       4 
8 
     | 
    
         
             
                  t.references :feature, null: false, foreign_key: { to_table: :togglefy_features }
         
     | 
| 
       5 
9 
     | 
    
         
             
                  t.references :assignable, polymorphic: true, null: false
         
     | 
| 
       6 
10 
     | 
    
         
             
                  t.timestamps
         
     | 
| 
       7 
11 
     | 
    
         
             
                end
         
     | 
| 
       8 
     | 
    
         
            -
                add_index :togglefy_feature_assignments, [ 
     | 
| 
      
 12 
     | 
    
         
            +
                add_index :togglefy_feature_assignments, %i[feature_id assignable_type assignable_id], unique: true,
         
     | 
| 
      
 13 
     | 
    
         
            +
                                                                                                       name: "index_togglefy_assignments_uniqueness"
         
     | 
| 
       9 
14 
     | 
    
         
             
              end
         
     | 
| 
       10 
     | 
    
         
            -
            end
         
     | 
| 
      
 15 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,4 +1,8 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
             
     | 
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            rails_version = "#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            class CreateTogglefyFeatures < ActiveRecord::Migration[rails_version]
         
     | 
| 
       2 
6 
     | 
    
         
             
              def change
         
     | 
| 
       3 
7 
     | 
    
         
             
                create_table :togglefy_features do |t|
         
     | 
| 
       4 
8 
     | 
    
         
             
                  t.string :name, null: false
         
     | 
    
        data/lib/togglefy/assignable.rb
    CHANGED
    
    | 
         @@ -1,3 +1,5 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            require "active_support/concern"
         
     | 
| 
       2 
4 
     | 
    
         | 
| 
       3 
5 
     | 
    
         
             
            module Togglefy
         
     | 
| 
         @@ -8,24 +10,25 @@ module Togglefy 
     | 
|
| 
       8 
10 
     | 
    
         
             
                  has_many :feature_assignments, as: :assignable, class_name: "Togglefy::FeatureAssignment"
         
     | 
| 
       9 
11 
     | 
    
         
             
                  has_many :features, through: :feature_assignments, class_name: "Togglefy::Feature"
         
     | 
| 
       10 
12 
     | 
    
         | 
| 
       11 
     | 
    
         
            -
                  scope :with_features,  
     | 
| 
      
 13 
     | 
    
         
            +
                  scope :with_features, lambda { |feature_ids|
         
     | 
| 
       12 
14 
     | 
    
         
             
                    joins(:feature_assignments)
         
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
      
 15 
     | 
    
         
            +
                      .where(feature_assignments: {
         
     | 
| 
      
 16 
     | 
    
         
            +
                               feature_id: feature_ids
         
     | 
| 
      
 17 
     | 
    
         
            +
                             })
         
     | 
| 
      
 18 
     | 
    
         
            +
                      .distinct
         
     | 
| 
       17 
19 
     | 
    
         
             
                  }
         
     | 
| 
       18 
20 
     | 
    
         | 
| 
       19 
     | 
    
         
            -
                  scope :without_features,  
     | 
| 
      
 21 
     | 
    
         
            +
                  scope :without_features, lambda { |feature_ids|
         
     | 
| 
       20 
22 
     | 
    
         
             
                    joins(left_join_on_features(feature_ids))
         
     | 
| 
       21 
23 
     | 
    
         
             
                      .where("fa.id IS NULL")
         
     | 
| 
       22 
24 
     | 
    
         
             
                      .distinct
         
     | 
| 
       23 
25 
     | 
    
         
             
                  }
         
     | 
| 
       24 
26 
     | 
    
         
             
                end
         
     | 
| 
       25 
27 
     | 
    
         | 
| 
       26 
     | 
    
         
            -
                def  
     | 
| 
      
 28 
     | 
    
         
            +
                def feature?(identifier)
         
     | 
| 
       27 
29 
     | 
    
         
             
                  features.exists?(identifier: identifier.to_s)
         
     | 
| 
       28 
30 
     | 
    
         
             
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
                alias has_feature? feature?
         
     | 
| 
       29 
32 
     | 
    
         | 
| 
       30 
33 
     | 
    
         
             
                def add_feature(feature)
         
     | 
| 
       31 
34 
     | 
    
         
             
                  feature = find_feature!(feature)
         
     | 
| 
         @@ -51,8 +54,8 @@ module Togglefy 
     | 
|
| 
       51 
54 
     | 
    
         | 
| 
       52 
55 
     | 
    
         
             
                class_methods do
         
     | 
| 
       53 
56 
     | 
    
         
             
                  def left_join_on_features(feature_ids)
         
     | 
| 
       54 
     | 
    
         
            -
                    table =  
     | 
| 
       55 
     | 
    
         
            -
                    type =  
     | 
| 
      
 57 
     | 
    
         
            +
                    table = table_name
         
     | 
| 
      
 58 
     | 
    
         
            +
                    type = name
         
     | 
| 
       56 
59 
     | 
    
         | 
| 
       57 
60 
     | 
    
         
             
                    <<~SQL.squish
         
     | 
| 
       58 
61 
     | 
    
         
             
                      LEFT JOIN togglefy_feature_assignments fa
         
     | 
| 
         @@ -63,4 +66,4 @@ module Togglefy 
     | 
|
| 
       63 
66 
     | 
    
         
             
                  end
         
     | 
| 
       64 
67 
     | 
    
         
             
                end
         
     | 
| 
       65 
68 
     | 
    
         
             
              end
         
     | 
| 
       66 
     | 
    
         
            -
            end
         
     | 
| 
      
 69 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/togglefy/engine.rb
    CHANGED
    
    
    
        data/lib/togglefy/exceptions.rb
    CHANGED
    
    
| 
         @@ -1,5 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module Togglefy
         
     | 
| 
       2 
4 
     | 
    
         
             
              class FeatureQuery
         
     | 
| 
      
 5 
     | 
    
         
            +
                FILTERS = {
         
     | 
| 
      
 6 
     | 
    
         
            +
                  identifier: :identifier,
         
     | 
| 
      
 7 
     | 
    
         
            +
                  group: :for_group,
         
     | 
| 
      
 8 
     | 
    
         
            +
                  role: :for_group,
         
     | 
| 
      
 9 
     | 
    
         
            +
                  environment: :for_environment,
         
     | 
| 
      
 10 
     | 
    
         
            +
                  env: :for_environment,
         
     | 
| 
      
 11 
     | 
    
         
            +
                  tenant_id: :for_tenant,
         
     | 
| 
      
 12 
     | 
    
         
            +
                  status: :with_status
         
     | 
| 
      
 13 
     | 
    
         
            +
                }.freeze
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
       3 
15 
     | 
    
         
             
                def features
         
     | 
| 
       4 
16 
     | 
    
         
             
                  Togglefy::Feature.all
         
     | 
| 
       5 
17 
     | 
    
         
             
                end
         
     | 
| 
         @@ -43,14 +55,14 @@ module Togglefy 
     | 
|
| 
       43 
55 
     | 
    
         
             
                end
         
     | 
| 
       44 
56 
     | 
    
         | 
| 
       45 
57 
     | 
    
         
             
                def for_filters(filters)
         
     | 
| 
       46 
     | 
    
         
            -
                  Togglefy::Feature
         
     | 
| 
       47 
     | 
    
         
            -
                     
     | 
| 
       48 
     | 
    
         
            -
                     
     | 
| 
       49 
     | 
    
         
            -
             
     | 
| 
       50 
     | 
    
         
            -
                    . 
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
      
 58 
     | 
    
         
            +
                  FILTERS.reduce(Togglefy::Feature) do |query, (key, scope)|
         
     | 
| 
      
 59 
     | 
    
         
            +
                    value = filters[key]
         
     | 
| 
      
 60 
     | 
    
         
            +
                    next query unless filters.key?(key) && nil_or_not_blank?(value)
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                    query.public_send(scope, value)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
       52 
64 
     | 
    
         
             
                end
         
     | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
       54 
66 
     | 
    
         
             
                private
         
     | 
| 
       55 
67 
     | 
    
         | 
| 
       56 
68 
     | 
    
         
             
                def safe_chain(query, method, value, apply_if: true)
         
     | 
| 
         @@ -61,4 +73,4 @@ module Togglefy 
     | 
|
| 
       61 
73 
     | 
    
         
             
                  value.nil? || !value.blank?
         
     | 
| 
       62 
74 
     | 
    
         
             
                end
         
     | 
| 
       63 
75 
     | 
    
         
             
              end
         
     | 
| 
       64 
     | 
    
         
            -
            end
         
     | 
| 
      
 76 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/togglefy/featureable.rb
    CHANGED
    
    
| 
         @@ -1,3 +1,5 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module Togglefy
         
     | 
| 
       2 
4 
     | 
    
         
             
              class BulkToggler
         
     | 
| 
       3 
5 
     | 
    
         
             
                ALLOWED_ASSIGNABLE_FILTERS = %i[group role environment env tenant_id].freeze
         
     | 
| 
         @@ -20,80 +22,33 @@ module Togglefy 
     | 
|
| 
       20 
22 
     | 
    
         | 
| 
       21 
23 
     | 
    
         
             
                def toggle(action, identifiers, filters)
         
     | 
| 
       22 
24 
     | 
    
         
             
                  identifiers = Array(identifiers)
         
     | 
| 
       23 
     | 
    
         
            -
                  features =  
     | 
| 
       24 
     | 
    
         
            -
                    filters: {identifier: identifiers}.merge(build_scope_filters(filters))
         
     | 
| 
       25 
     | 
    
         
            -
                  ).to_a
         
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
                  raise Togglefy::FeatureNotFound if features.empty?
         
     | 
| 
      
 25 
     | 
    
         
            +
                  features = get_features(identifiers, filters)
         
     | 
| 
       28 
26 
     | 
    
         | 
| 
       29 
27 
     | 
    
         
             
                  feature_ids = features.map(&:id)
         
     | 
| 
       30 
28 
     | 
    
         | 
| 
       31 
     | 
    
         
            -
                  assignables =  
     | 
| 
       32 
     | 
    
         
            -
                    klass.without_features(feature_ids)
         
     | 
| 
       33 
     | 
    
         
            -
                  else
         
     | 
| 
       34 
     | 
    
         
            -
                    klass.with_features(feature_ids)
         
     | 
| 
       35 
     | 
    
         
            -
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
                  assignables = get_assignables(action, feature_ids)
         
     | 
| 
       36 
30 
     | 
    
         | 
| 
       37 
     | 
    
         
            -
                  raise Togglefy::AssignablesNotFound.new(klass, identifiers, filters) if assignables.empty?
         
     | 
| 
       38 
     | 
    
         
            -
                  
         
     | 
| 
       39 
31 
     | 
    
         
             
                  assignables = sample_assignables(assignables, filters[:percentage]) if filters[:percentage]
         
     | 
| 
       40 
32 
     | 
    
         | 
| 
       41 
     | 
    
         
            -
                   
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
       44 
     | 
    
         
            -
                    feature_id: features.map(&:id)
         
     | 
| 
       45 
     | 
    
         
            -
                  ).pluck(:assignable_id, :feature_id)
         
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
     | 
    
         
            -
                  existing_lookup = Set.new(existing_assignments)
         
     | 
| 
       48 
     | 
    
         
            -
                  
         
     | 
| 
       49 
     | 
    
         
            -
                  if action == :enable
         
     | 
| 
       50 
     | 
    
         
            -
                    rows = []
         
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
                    assignables.each do |assignable|
         
     | 
| 
       53 
     | 
    
         
            -
                      features.each do |feature|
         
     | 
| 
       54 
     | 
    
         
            -
                        key = [assignable.id, feature.id]
         
     | 
| 
       55 
     | 
    
         
            -
                        next if existing_lookup.include?(key)
         
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
                        rows << {
         
     | 
| 
       58 
     | 
    
         
            -
                          assignable_id: assignable.id,
         
     | 
| 
       59 
     | 
    
         
            -
                          assignable_type: assignable.class.name,
         
     | 
| 
       60 
     | 
    
         
            -
                          feature_id: feature.id
         
     | 
| 
       61 
     | 
    
         
            -
                        }
         
     | 
| 
       62 
     | 
    
         
            -
                      end
         
     | 
| 
       63 
     | 
    
         
            -
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
                  enable_flow(assignables, features, identifiers) if action == :enable
         
     | 
| 
      
 34 
     | 
    
         
            +
                  disable_flow(assignables, features, identifiers) if action == :disable
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
       64 
36 
     | 
    
         | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
                    rescue => error
         
     | 
| 
       68 
     | 
    
         
            -
                      raise Togglefy::BulkToggleFailed.new(
         
     | 
| 
       69 
     | 
    
         
            -
                        "Bulk toggle enable failed for #{klass.name} with identifiers #{identifiers.inspect}",
         
     | 
| 
       70 
     | 
    
         
            -
                        error
         
     | 
| 
       71 
     | 
    
         
            -
                      )
         
     | 
| 
       72 
     | 
    
         
            -
                    end
         
     | 
| 
       73 
     | 
    
         
            -
                  elsif action == :disable
         
     | 
| 
       74 
     | 
    
         
            -
                    ids_to_remove = []
         
     | 
| 
       75 
     | 
    
         
            -
                    assignables.each do |assignable|
         
     | 
| 
       76 
     | 
    
         
            -
                      features.each do |feature|
         
     | 
| 
       77 
     | 
    
         
            -
                        key = [assignable.id, feature.id]
         
     | 
| 
       78 
     | 
    
         
            -
                        ids_to_remove << key if existing_lookup.include?(key)
         
     | 
| 
       79 
     | 
    
         
            -
                      end
         
     | 
| 
       80 
     | 
    
         
            -
                    end
         
     | 
| 
      
 37 
     | 
    
         
            +
                def get_features(identifiers, filters)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  features = Togglefy.for_filters(filters: { identifier: identifiers }.merge(build_scope_filters(filters))).to_a
         
     | 
| 
       81 
39 
     | 
    
         | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
       83 
     | 
    
         
            -
             
     | 
| 
       84 
     | 
    
         
            -
             
     | 
| 
       85 
     | 
    
         
            -
             
     | 
| 
       86 
     | 
    
         
            -
             
     | 
| 
       87 
     | 
    
         
            -
             
     | 
| 
       88 
     | 
    
         
            -
             
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
       90 
     | 
    
         
            -
             
     | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
       92 
     | 
    
         
            -
             
     | 
| 
       93 
     | 
    
         
            -
             
     | 
| 
       94 
     | 
    
         
            -
                      )
         
     | 
| 
       95 
     | 
    
         
            -
                    end
         
     | 
| 
       96 
     | 
    
         
            -
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
                  raise Togglefy::FeatureNotFound if features.empty?
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                  features
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                def get_assignables(action, feature_ids)
         
     | 
| 
      
 46 
     | 
    
         
            +
                  assignables = klass.without_features(feature_ids) if action == :enable
         
     | 
| 
      
 47 
     | 
    
         
            +
                  assignables = klass.with_features(feature_ids) if action == :disable
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  raise Togglefy::AssignablesNotFound, klass if assignables.empty?
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  assignables
         
     | 
| 
       97 
52 
     | 
    
         
             
                end
         
     | 
| 
       98 
53 
     | 
    
         | 
| 
       99 
54 
     | 
    
         
             
                def build_scope_filters(filters)
         
     | 
| 
         @@ -104,5 +59,51 @@ module Togglefy 
     | 
|
| 
       104 
59 
     | 
    
         
             
                  count = (assignables.size * percentage.to_f / 100).round
         
     | 
| 
       105 
60 
     | 
    
         
             
                  assignables.sample(count)
         
     | 
| 
       106 
61 
     | 
    
         
             
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                def enable_flow(assignables, features, identifiers)
         
     | 
| 
      
 64 
     | 
    
         
            +
                  rows = []
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                  assignables.each do |assignable|
         
     | 
| 
      
 67 
     | 
    
         
            +
                    features.each do |feature|
         
     | 
| 
      
 68 
     | 
    
         
            +
                      rows << { assignable_id: assignable.id, assignable_type: assignable.class.name, feature_id: feature.id }
         
     | 
| 
      
 69 
     | 
    
         
            +
                    end
         
     | 
| 
      
 70 
     | 
    
         
            +
                  end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                  mass_insert(rows, identifiers)
         
     | 
| 
      
 73 
     | 
    
         
            +
                end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                def mass_insert(rows, identifiers)
         
     | 
| 
      
 76 
     | 
    
         
            +
                  Togglefy::FeatureAssignment.insert_all(rows) if rows.any?
         
     | 
| 
      
 77 
     | 
    
         
            +
                rescue Togglefy::Error => e
         
     | 
| 
      
 78 
     | 
    
         
            +
                  raise Togglefy::BulkToggleFailed.new(
         
     | 
| 
      
 79 
     | 
    
         
            +
                    "Bulk toggle enable failed for #{klass.name} with identifiers #{identifiers.inspect}",
         
     | 
| 
      
 80 
     | 
    
         
            +
                    e
         
     | 
| 
      
 81 
     | 
    
         
            +
                  )
         
     | 
| 
      
 82 
     | 
    
         
            +
                end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                def disable_flow(assignables, features, identifiers)
         
     | 
| 
      
 85 
     | 
    
         
            +
                  ids_to_remove = []
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                  assignables.each do |assignable|
         
     | 
| 
      
 88 
     | 
    
         
            +
                    features.each do |feature|
         
     | 
| 
      
 89 
     | 
    
         
            +
                      ids_to_remove << [assignable.id, feature.id]
         
     | 
| 
      
 90 
     | 
    
         
            +
                    end
         
     | 
| 
      
 91 
     | 
    
         
            +
                  end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                  mass_delete(ids_to_remove, identifiers)
         
     | 
| 
      
 94 
     | 
    
         
            +
                end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                def mass_delete(ids_to_remove, identifiers)
         
     | 
| 
      
 97 
     | 
    
         
            +
                  if ids_to_remove.any?
         
     | 
| 
      
 98 
     | 
    
         
            +
                    Togglefy::FeatureAssignment.where(
         
     | 
| 
      
 99 
     | 
    
         
            +
                      assignable_id: ids_to_remove.map(&:first), assignable_type: klass.name, feature_id: ids_to_remove.map(&:last)
         
     | 
| 
      
 100 
     | 
    
         
            +
                    ).delete_all
         
     | 
| 
      
 101 
     | 
    
         
            +
                  end
         
     | 
| 
      
 102 
     | 
    
         
            +
                rescue Togglefy::Error => e
         
     | 
| 
      
 103 
     | 
    
         
            +
                  raise Togglefy::BulkToggleFailed.new(
         
     | 
| 
      
 104 
     | 
    
         
            +
                    "Bulk toggle disable failed for #{klass.name} with identifiers #{identifiers.inspect}",
         
     | 
| 
      
 105 
     | 
    
         
            +
                    e
         
     | 
| 
      
 106 
     | 
    
         
            +
                  )
         
     | 
| 
      
 107 
     | 
    
         
            +
                end
         
     | 
| 
       107 
108 
     | 
    
         
             
              end
         
     | 
| 
       108 
109 
     | 
    
         
             
            end
         
     | 
    
        data/lib/togglefy/version.rb
    CHANGED
    
    
    
        data/lib/togglefy.rb
    CHANGED
    
    | 
         @@ -21,11 +21,11 @@ module Togglefy 
     | 
|
| 
       21 
21 
     | 
    
         
             
              def self.feature(identifier)
         
     | 
| 
       22 
22 
     | 
    
         
             
                FeatureQuery.new.feature(identifier)
         
     | 
| 
       23 
23 
     | 
    
         
             
              end
         
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
       25 
25 
     | 
    
         
             
              def self.for_type(klass)
         
     | 
| 
       26 
26 
     | 
    
         
             
                FeatureQuery.new.for_type(klass)
         
     | 
| 
       27 
27 
     | 
    
         
             
              end
         
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
       29 
29 
     | 
    
         
             
              def self.for_group(group)
         
     | 
| 
       30 
30 
     | 
    
         
             
                FeatureQuery.new.for_group(group)
         
     | 
| 
       31 
31 
     | 
    
         
             
              end
         
     | 
| 
         @@ -93,20 +93,20 @@ module Togglefy 
     | 
|
| 
       93 
93 
     | 
    
         
             
                Togglefy::ScopedBulkWrapper.new(klass)
         
     | 
| 
       94 
94 
     | 
    
         
             
              end
         
     | 
| 
       95 
95 
     | 
    
         | 
| 
       96 
     | 
    
         
            -
              class <<self
         
     | 
| 
      
 96 
     | 
    
         
            +
              class << self
         
     | 
| 
       97 
97 
     | 
    
         
             
                # FeatureQuery
         
     | 
| 
       98 
     | 
    
         
            -
                 
     | 
| 
       99 
     | 
    
         
            -
                 
     | 
| 
      
 98 
     | 
    
         
            +
                alias for_role for_group
         
     | 
| 
      
 99 
     | 
    
         
            +
                alias without_role without_group
         
     | 
| 
       100 
100 
     | 
    
         | 
| 
       101 
     | 
    
         
            -
                 
     | 
| 
       102 
     | 
    
         
            -
                 
     | 
| 
      
 101 
     | 
    
         
            +
                alias for_env for_environment
         
     | 
| 
      
 102 
     | 
    
         
            +
                alias without_env without_environment
         
     | 
| 
       103 
103 
     | 
    
         | 
| 
       104 
104 
     | 
    
         
             
                # FeatureManager
         
     | 
| 
       105 
     | 
    
         
            -
                 
     | 
| 
       106 
     | 
    
         
            -
                 
     | 
| 
       107 
     | 
    
         
            -
                 
     | 
| 
       108 
     | 
    
         
            -
                 
     | 
| 
       109 
     | 
    
         
            -
                 
     | 
| 
       110 
     | 
    
         
            -
                 
     | 
| 
      
 105 
     | 
    
         
            +
                alias create_feature create
         
     | 
| 
      
 106 
     | 
    
         
            +
                alias update_feature update
         
     | 
| 
      
 107 
     | 
    
         
            +
                alias toggle_feature toggle
         
     | 
| 
      
 108 
     | 
    
         
            +
                alias activate_feature active!
         
     | 
| 
      
 109 
     | 
    
         
            +
                alias inactivate_feature inactive!
         
     | 
| 
      
 110 
     | 
    
         
            +
                alias destroy_feature destroy
         
     | 
| 
       111 
111 
     | 
    
         
             
              end
         
     | 
| 
       112 
112 
     | 
    
         
             
            end
         
     | 
    
        data/togglefy.gemspec
    CHANGED
    
    | 
         @@ -22,13 +22,19 @@ Gem::Specification.new do |spec| 
     | 
|
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
              # Specify which files should be added to the gem when it is released.
         
     | 
| 
       24 
24 
     | 
    
         
             
              # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
         
     | 
| 
       25 
     | 
    
         
            -
               
     | 
| 
      
 25 
     | 
    
         
            +
              File.basename(__FILE__)
         
     | 
| 
       26 
26 
     | 
    
         
             
              spec.files = Dir.glob("lib/**/*") +
         
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
      
 27 
     | 
    
         
            +
                           Dir.glob("app/**/*") +
         
     | 
| 
      
 28 
     | 
    
         
            +
                           Dir.glob("config/**/*") +
         
     | 
| 
      
 29 
     | 
    
         
            +
                           %w[LICENSE.txt README.md Rakefile togglefy.gemspec]
         
     | 
| 
       30 
30 
     | 
    
         | 
| 
       31 
31 
     | 
    
         
             
              spec.bindir = "exe"
         
     | 
| 
       32 
32 
     | 
    
         
             
              spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
         
     | 
| 
       33 
33 
     | 
    
         
             
              spec.require_paths = ["lib"]
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              spec.add_development_dependency "bootsnap", "~> 1.17"
         
     | 
| 
      
 36 
     | 
    
         
            +
              spec.add_development_dependency "database_cleaner-active_record", "~> 2.1"
         
     | 
| 
      
 37 
     | 
    
         
            +
              spec.add_development_dependency "rails", "~> 8.0.2"
         
     | 
| 
      
 38 
     | 
    
         
            +
              spec.add_development_dependency "rspec-rails", "~> 7.1.1"
         
     | 
| 
      
 39 
     | 
    
         
            +
              spec.add_development_dependency "sqlite3", "~> 2.1"
         
     | 
| 
       34 
40 
     | 
    
         
             
            end
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,84 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: togglefy
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 1. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 1.2.0
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Gabriel Azevedo
         
     | 
| 
       8 
8 
     | 
    
         
             
            bindir: exe
         
     | 
| 
       9 
9 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       10 
     | 
    
         
            -
            date: 2025-04- 
     | 
| 
       11 
     | 
    
         
            -
            dependencies: 
     | 
| 
      
 10 
     | 
    
         
            +
            date: 2025-04-29 00:00:00.000000000 Z
         
     | 
| 
      
 11 
     | 
    
         
            +
            dependencies:
         
     | 
| 
      
 12 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 13 
     | 
    
         
            +
              name: bootsnap
         
     | 
| 
      
 14 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 15 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 16 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 17 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 18 
     | 
    
         
            +
                    version: '1.17'
         
     | 
| 
      
 19 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 20 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 21 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 22 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 23 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 24 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 25 
     | 
    
         
            +
                    version: '1.17'
         
     | 
| 
      
 26 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 27 
     | 
    
         
            +
              name: database_cleaner-active_record
         
     | 
| 
      
 28 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 29 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 30 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 31 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 32 
     | 
    
         
            +
                    version: '2.1'
         
     | 
| 
      
 33 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 34 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 35 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 36 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 37 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 38 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 39 
     | 
    
         
            +
                    version: '2.1'
         
     | 
| 
      
 40 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 41 
     | 
    
         
            +
              name: rails
         
     | 
| 
      
 42 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 43 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 44 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 45 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 46 
     | 
    
         
            +
                    version: 8.0.2
         
     | 
| 
      
 47 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 48 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 49 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 50 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 51 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 52 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 53 
     | 
    
         
            +
                    version: 8.0.2
         
     | 
| 
      
 54 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 55 
     | 
    
         
            +
              name: rspec-rails
         
     | 
| 
      
 56 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 57 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 58 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 59 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 60 
     | 
    
         
            +
                    version: 7.1.1
         
     | 
| 
      
 61 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 62 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 63 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 64 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 65 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 66 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 67 
     | 
    
         
            +
                    version: 7.1.1
         
     | 
| 
      
 68 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 69 
     | 
    
         
            +
              name: sqlite3
         
     | 
| 
      
 70 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 71 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 72 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 73 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 74 
     | 
    
         
            +
                    version: '2.1'
         
     | 
| 
      
 75 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 76 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 77 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 78 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 79 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 80 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 81 
     | 
    
         
            +
                    version: '2.1'
         
     | 
| 
       12 
82 
     | 
    
         
             
            description: Togglefy is a feature management Rails gem to help you control which
         
     | 
| 
       13 
83 
     | 
    
         
             
              features an user or a group has access to.
         
     | 
| 
       14 
84 
     | 
    
         
             
            email:
         
     | 
| 
         @@ -19,6 +89,7 @@ extra_rdoc_files: [] 
     | 
|
| 
       19 
89 
     | 
    
         
             
            files:
         
     | 
| 
       20 
90 
     | 
    
         
             
            - LICENSE.txt
         
     | 
| 
       21 
91 
     | 
    
         
             
            - README.md
         
     | 
| 
      
 92 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
       22 
93 
     | 
    
         
             
            - app/models/togglefy/feature.rb
         
     | 
| 
       23 
94 
     | 
    
         
             
            - app/models/togglefy/feature_assignment.rb
         
     | 
| 
       24 
95 
     | 
    
         
             
            - lib/generators/togglefy/install_generator.rb
         
     |