active_flags 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: bfaa18819393cb9c991c16d105fdb92b6c8f062142f1ca02dc11181612e96fbe
4
+ data.tar.gz: f1a371f52a51fa31d31ffb5b51173ae35034060098991d8ee12e78d64791ec04
5
+ SHA512:
6
+ metadata.gz: 9470fa8f5b37a712f228d367747d2c56562c41f7ee13c2060e40c821bc4a8092a9bed67a3efb23ef0c79b0f060f0a530f7c9edefc426fd8a49bfd74dfb98265f
7
+ data.tar.gz: b85d3dcf82c39838dd7d1e476c142c1f1a29cc766b2fad4756f8e84d59f5521cc32b5a3cc508cda174baa412c221ed2d0f1ebb3ad9276de886f5d83fa3dd8f2a
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2019 Nathan Huberty
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,75 @@
1
+ # ActiveFlags
2
+ Active Flags allows you to use automatic flags on models. You won't have to create useless booleans with view logic in your core tables. They should not have been there in the first place, let Active Flags handle them for you!
3
+
4
+ ## Installation
5
+
6
+ (You need at least rails 5.0 to use the gem)
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'active_flags'
11
+ ```
12
+
13
+ And then execute:
14
+ ```bash
15
+ $ bundle
16
+ ```
17
+
18
+ Or install it yourself as:
19
+ ```bash
20
+ $ gem install active_flags
21
+ ```
22
+
23
+ Then import Active Flags' migrations
24
+ ```bash
25
+ $ bin/rails active_flags:install:migrations
26
+ ```
27
+
28
+ Adapt them if needed and run db:migrate
29
+ ```bash
30
+ $ rails db:migrate
31
+ ```
32
+
33
+ ## Usage
34
+ Let's say you're building a networking app, with users connecting each other.
35
+ But you want it to be so relevant that it only makes active users (connecting often enough) visibles on the search.
36
+ To do so you would add a boolean `active` or `visible` in your user's table.
37
+
38
+ It works, but it is view logic and shouldn't be there. Imagine your app is growing and you have 10 more booleans on your user table, and then 10 more on another model. It will only pollute your tables.
39
+
40
+ Once Active Flags is set, you can easily declare that your model has flags like that:
41
+
42
+ ```ruby
43
+ class User < ApplicationRecord
44
+ has_flags :visible, :active
45
+ end
46
+ ```
47
+
48
+ And that's it!
49
+ You can now add flags on a user like that:
50
+
51
+ ```ruby
52
+ user.flags = { visible: 'true', active: 'true' }
53
+ user.save!
54
+ ```
55
+
56
+ A flag won't be saved if you don't explicitly declare it as has_flags attributes in the model.
57
+
58
+ But if you do not want to handle explicit flags, you could also declare:
59
+
60
+ ```ruby
61
+ class User < ApplicationRecord
62
+ has_flags
63
+ end
64
+ ```
65
+
66
+ And then you can declare as much flags as you want with no restriction:
67
+ ```ruby
68
+ user.update!(flags: { visible: 'true', active: 'true', diet: 'vegan', power: 'super saiyan' })
69
+ ```
70
+
71
+ ## Contributing
72
+ https://github.com/FidMe/active_flags
73
+
74
+ ## License
75
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,32 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'ActiveFlags'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+ load 'rails/tasks/statistics.rake'
21
+
22
+ require 'bundler/gem_tasks'
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'test'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = false
30
+ end
31
+
32
+ task default: :test
@@ -0,0 +1 @@
1
+ //= link_directory ../stylesheets/active_flags .css
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,5 @@
1
+ module ActiveFlags
2
+ class ApplicationController < ActionController::Base
3
+ protect_from_forgery with: :exception
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ module ActiveFlags
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module ActiveFlags
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module ActiveFlags
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: 'from@example.com'
4
+ layout 'mailer'
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module ActiveFlags
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ module ActiveFlags
2
+ class Flag < ApplicationRecord
3
+ belongs_to :subject, polymorphic: true
4
+
5
+ validates :subject, :key, :value, presence: true
6
+ validates :key, uniqueness: { scope: :subject }
7
+ end
8
+ end
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Active flags</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+
8
+ <%= stylesheet_link_tag "active_flags/application", media: "all" %>
9
+ </head>
10
+ <body>
11
+
12
+ <%= yield %>
13
+
14
+ </body>
15
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,2 @@
1
+ ActiveFlags::Engine.routes.draw do
2
+ end
@@ -0,0 +1,12 @@
1
+ class CreateActiveFlagsFlags < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :active_flags_flags do |t|
4
+ t.string :key
5
+ t.string :value
6
+ t.integer :subject_id
7
+ t.string :subject_type
8
+
9
+ t.timestamps
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ class AddIndexesOnSubjectIdAndType < ActiveRecord::Migration[6.0]
2
+ def change
3
+ add_index :active_flags_flags, [:subject_id, :subject_type]
4
+ end
5
+ end
@@ -0,0 +1,10 @@
1
+ # require_relative 'flaggable'
2
+
3
+ module ActiveFlags
4
+ class Engine < ::Rails::Engine
5
+ isolate_namespace ActiveFlags
6
+ config.to_prepare do
7
+ ActiveRecord::Base.include ActiveFlags
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,16 @@
1
+ module ActiveFlags
2
+ module Handler
3
+ class FlagBuilder
4
+ def initialize(resource, flag_attributes)
5
+ @resource = resource
6
+ @flag_attributes = flag_attributes
7
+ end
8
+
9
+ def save
10
+ @resource.flags << ActiveFlags::Flag.find_or_initialize_by(subject: @resource, key: @flag_attributes[:key]) do |flag_to_create|
11
+ flag_to_create.value = @flag_attributes[:value]
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,22 @@
1
+ require_relative 'flag_mappers/key_value_mapper'
2
+ require_relative 'flag_mappers/authorizer'
3
+
4
+ module ActiveFlags
5
+ module Handler
6
+ class FlagMapper
7
+ def initialize(authorized_flags = {}, flags)
8
+ @authorized_flags = authorized_flags
9
+ @flags = flags
10
+ end
11
+
12
+ def remap
13
+ @flags = FlagMappers::Authorizer.authorize(@authorized_flags, @flags)
14
+ FlagMappers::KeyValueMapper.remap(@flags)
15
+ end
16
+
17
+ def self.remap(authorized_flags, flags)
18
+ new(authorized_flags, flags).remap
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ module ActiveFlags
2
+ module Handler
3
+ module FlagMappers
4
+ class Authorizer
5
+ def initialize(authorized_flags = {}, flags)
6
+ @authorized_flags = authorized_flags
7
+ @flags = flags
8
+ end
9
+
10
+ def authorize
11
+ return @flags if @authorized_flags.empty?
12
+ @flags.select do |flag_name, value|
13
+ @authorized_flags.include?(flag_name)
14
+ end
15
+ end
16
+
17
+ def self.authorize(authorized_flags, flags)
18
+ new(authorized_flags, flags).authorize
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,22 @@
1
+ module ActiveFlags
2
+ module Handler
3
+ module FlagMappers
4
+ class KeyValueMapper
5
+
6
+ def initialize(hash_to_map)
7
+ @hash_to_map = hash_to_map
8
+ end
9
+
10
+ def remap
11
+ @hash_to_map.map do |key, value|
12
+ { key: key, value: value }
13
+ end
14
+ end
15
+
16
+ def self.remap(hash_of_flags)
17
+ new(hash_of_flags).remap
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module ActiveFlags
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,19 @@
1
+ require "active_flags/engine"
2
+ require_relative 'active_flags/handler/flag_mapper'
3
+ require_relative 'active_flags/handler/flag_builder'
4
+
5
+ module ActiveFlags
6
+ extend ActiveSupport::Concern
7
+
8
+ class_methods do
9
+ def has_flags(*authorized_flags)
10
+ has_many :flags, class_name: 'ActiveFlags::Flag', as: :subject
11
+
12
+ define_method(:flags=) do |flags|
13
+ Handler::FlagMapper.remap(authorized_flags, flags.symbolize_keys).each do |flag_attributes|
14
+ Handler::FlagBuilder.new(self, flag_attributes).save
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :active_flags do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_flags
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Nathan Huberty
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-03-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '5.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: sqlite3
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.3.6
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.3.6
41
+ description: Easily declare flags for your models.
42
+ email:
43
+ - nathan.huberty@orange.fr
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - MIT-LICENSE
49
+ - README.md
50
+ - Rakefile
51
+ - app/assets/config/active_flags_manifest.js
52
+ - app/assets/stylesheets/active_flags/application.css
53
+ - app/controllers/active_flags/application_controller.rb
54
+ - app/helpers/active_flags/application_helper.rb
55
+ - app/jobs/active_flags/application_job.rb
56
+ - app/mailers/active_flags/application_mailer.rb
57
+ - app/models/active_flags/application_record.rb
58
+ - app/models/active_flags/flag.rb
59
+ - app/views/layouts/active_flags/application.html.erb
60
+ - config/routes.rb
61
+ - db/migrate/20190304151043_create_active_flags_flags.rb
62
+ - db/migrate/20190305091129_add_indexes_on_subject_id_and_type.rb
63
+ - lib/active_flags.rb
64
+ - lib/active_flags/engine.rb
65
+ - lib/active_flags/handler/flag_builder.rb
66
+ - lib/active_flags/handler/flag_mapper.rb
67
+ - lib/active_flags/handler/flag_mappers/authorizer.rb
68
+ - lib/active_flags/handler/flag_mappers/key_value_mapper.rb
69
+ - lib/active_flags/version.rb
70
+ - lib/tasks/active_flags_tasks.rake
71
+ homepage: https://github.com/FidMe/active_flags
72
+ licenses:
73
+ - MIT
74
+ metadata: {}
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubygems_version: 3.0.1
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: Easily declare flags for your models.
94
+ test_files: []