simple_enum-multiple 0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c89b6aec44c60fd0f92340755e106fae10546925
4
+ data.tar.gz: 1a1b9dd5c830ccb0db9de912f3894dc0ab3924f0
5
+ SHA512:
6
+ metadata.gz: 14472b37550061066af8ac2eaefc98972ae007871e174b5d6299b3a40044207f7d9f827dce4378037d9d50339fd3c9b457320ee438f015a8d363af1e5a86ff1e
7
+ data.tar.gz: 99d65fa4d15fd14dfb5b0e78f2d3d720d1250f5a3d25718b77ca40386936af6f6b6188827bc2cb2e89a4c92d0e3bde175dde8b1063ad362577ff562dcf319c41
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in simple_enum-multiple.gemspec
4
+ gemspec
5
+
6
+ # some development deps
7
+ gem 'activerecord-jdbcsqlite3-adapter', platform: :jruby
8
+ gem 'sqlite3', platform: :ruby
9
+ gem 'bson_ext', platform: :ruby
10
+
11
+ # Code coverage on CI only
12
+ gem 'codeclimate-test-reporter', group: :test, require: nil
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Theo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # SimpleEnum::Multiple
2
+
3
+ SimpleEnum::Multiple is extension of SimpleEnum, which brings multi-select enum support to SimpleEnum.
4
+
5
+ ## ActiveRecord Quick start
6
+
7
+ Add this to a model:
8
+ ```ruby
9
+ as_enum :tags, [:iphone, :ipad, :macbook], accessor: :join_table
10
+ ```
11
+
12
+ Then create the required tag_cds column using migrations:
13
+ ```ruby
14
+ class AddTagsColumnToPost < ActiveRecord::Migration
15
+ def change
16
+ create_join_table :posts, :tags
17
+ end
18
+ end
19
+ ```
20
+
21
+ It will store multi-enums data in a join table, if you don't want a join table, you may use `bitwise` accessor:
22
+
23
+ ```ruby
24
+ # Migration
25
+ add_column :posts, :tag_cds, :integer
26
+
27
+ # Model
28
+ as_enum :tags, [:iphone, :ipad, :macbook], accessor: :bitwise
29
+ ```
30
+
31
+ It will store multi-enums data in a integer column, and if you don't want SimpleEnum::Multiple manage how you store your data, you can use `multiple` accessor:
32
+
33
+ ```ruby
34
+ # Model
35
+ as_enum :tags, [:iphone, :ipad, :macbook], accessor: :multiple
36
+ ```
37
+
38
+ This accessor will not handle how the data saved in the database, so you have to use something like `serialize :tag_cds`, or implement your own [Coder](https://github.com/rails/rails/blob/master/activerecord/lib/active_record/coders/json.rb).
39
+
40
+
41
+ ## License
42
+
43
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
44
+
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ desc 'Default: run all unit tests for both ActiveRecord & Mongoid.'
4
+ task :default => :spec
5
+
6
+ desc 'Run rspec test suite'
7
+ task :spec do
8
+ sh 'bundle exec rspec spec/'
9
+ end
10
+
11
+ # Mongodb
12
+ directory "tmp/mongodb.data"
13
+ desc 'Run mongodb in tmp/'
14
+ task :mongodb => [:'tmp/mongodb.data'] do |t|
15
+ system "mongod", "--dbpath", "tmp/mongodb.data"
16
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "simple_enum/multiple"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,23 @@
1
+ require 'simple_enum/multiple/accessors/multiple_accessor'
2
+ require 'simple_enum/multiple/coders/bitwise'
3
+
4
+ module SimpleEnum
5
+ module Multiple
6
+ module Accessors
7
+ class BitwiseAccessor < MultipleAccessor
8
+ def init(klass)
9
+ source = self.source
10
+
11
+ klass.class_eval do
12
+ serialize source, SimpleEnum::Multiple::Coders::Bitwise
13
+ end
14
+ end
15
+
16
+ def scope(collection, value)
17
+ column = Arel::Nodes::Group.new(collection.arel_table[source]).to_sql
18
+ collection.where("#{column} >> ? & 1 = 1", value)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,97 @@
1
+ require 'simple_enum/multiple/accessors/multiple_accessor'
2
+
3
+ module SimpleEnum
4
+ module Multiple
5
+ module Accessors
6
+ class JoinTableAccessor < MultipleAccessor
7
+ attr_accessor :table, :foreign_key, :remote_key
8
+
9
+ def init(klass)
10
+ klass_table_name = klass.table_name.to_s
11
+ join_table_name = [klass_table_name, name.pluralize].sort.join("_").to_sym
12
+ table = self.table = Arel::Table.new(join_table_name)
13
+
14
+ source = self.source
15
+ name = self.name
16
+
17
+ foreign_key = self.foreign_key = klass_table_name.singularize.foreign_key
18
+ remote_key = self.remote_key = name.singularize.foreign_key
19
+
20
+ connection = ActiveRecord::Base.connection
21
+
22
+ klass.class_eval do
23
+ attr_accessor source
24
+
25
+ define_method :"#{source}_changed?" do
26
+ instance_variable_get(:"@#{source}") !=
27
+ instance_variable_get(:"@#{source}_was")
28
+ end
29
+
30
+ define_method :"#{source}_was" do
31
+ instance_variable = instance_variable_get(:"@#{source}_was")
32
+ return instance_variable if instance_variable
33
+ sql = table.where(table[foreign_key].eq(self.id))
34
+ .project(table[remote_key])
35
+ .to_sql
36
+ original_cds = connection.send(:select, sql).rows.map(&:first)
37
+ instance_variable_set(:"@#{source}_was", original_cds)
38
+ end
39
+
40
+ define_method source do
41
+ instance_variable = instance_variable_get(:"@#{source}")
42
+ return instance_variable if instance_variable
43
+ instance_variable_set(:"@#{source}", send(:"#{source}_was").dup)
44
+ end
45
+
46
+ define_method :"update_#{source}!" do
47
+ return unless send(:"#{source}_changed?")
48
+ original_cds = send(:"#{source}_was")
49
+ current_cds = send(source)
50
+
51
+ # if any enum been removed
52
+ if (original_cds - current_cds).any?
53
+ delete_sql = table.where(table[foreign_key].eq(self.id))
54
+ .where(table[remote_key].in(original_cds - current_cds))
55
+ .compile_delete
56
+ .to_sql
57
+ connection.send(:delete, delete_sql)
58
+ end
59
+
60
+ # if any enum been added
61
+ if (current_cds - original_cds).any?
62
+ insert_sql = table.create_insert.tap do |insert_manager|
63
+ insert_manager.into table
64
+ insert_manager.columns << table[foreign_key]
65
+ insert_manager.columns << table[remote_key]
66
+
67
+ values = (current_cds - original_cds).map do |id|
68
+ "(#{self.id}, #{id})"
69
+ end.join(", ")
70
+ insert_manager.values = Arel::Nodes::SqlLiteral.new("VALUES #{values}")
71
+ end.to_sql
72
+ connection.send(:insert, insert_sql)
73
+ end
74
+ end
75
+
76
+ after_save :"update_#{source}!"
77
+ end
78
+ end
79
+
80
+ def was(object)
81
+ fetch_keys(object.send(:"#{source}_was").to_a)
82
+ end
83
+
84
+ def changed?(object)
85
+ object.send(:"#{source}_changed?")
86
+ end
87
+
88
+ def scope(collection, value)
89
+ join = Arel::Nodes::Group.new(table).to_sql
90
+ on = collection.arel_table[collection.primary_key].eq(table[foreign_key]).to_sql
91
+ collection.joins("INNER JOIN #{join} ON #{on}")
92
+ .where(table[foreign_key].eq(value))
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,72 @@
1
+ require 'simple_enum/accessors/accessor'
2
+ require 'simple_enum/multiple/collection_proxy'
3
+
4
+ module SimpleEnum
5
+ module Multiple
6
+ module Accessors
7
+ class MultipleAccessor < SimpleEnum::Accessors::Accessor
8
+ def initialize(name, enum, source = nil, prefix = nil)
9
+ super
10
+ @source = source.to_s.presence || "#{@name.singularize}#{SimpleEnum.suffix.pluralize}"
11
+ end
12
+
13
+ def read(object)
14
+ CollectionProxy.new(read_before_type_cast(object), self)
15
+ end
16
+
17
+ def write(object, keys)
18
+ keys = filter_keys(Array.wrap(keys))
19
+ write_after_type_cast(object, fetch_values(keys)) && keys
20
+ end
21
+
22
+ def selected?(object, key = nil)
23
+ current = read_before_type_cast(object)
24
+ current.any? && if key
25
+ current.all? do
26
+ current.include?(enum.value(key))
27
+ end
28
+ else
29
+ true
30
+ end
31
+ end
32
+
33
+ def was(object)
34
+ fetch_keys(object.send(:attribute_was, source).to_a)
35
+ end
36
+
37
+ def scope(collection, value)
38
+ raise "scopes for accessor: :multiple are not supported!"
39
+ end
40
+
41
+ def filter_keys(keys)
42
+ keys.select do |key|
43
+ enum.value(key)
44
+ end
45
+ end
46
+
47
+ def fetch_keys(values)
48
+ values.map do |value|
49
+ enum.key(value)
50
+ end
51
+ end
52
+
53
+ def fetch_values(keys)
54
+ keys.map do |key|
55
+ enum.value(key)
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def read_before_type_cast(object)
62
+ result = super
63
+ unless result
64
+ result = []
65
+ write_after_type_cast(object, result)
66
+ end
67
+ result
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,16 @@
1
+ require 'simple_enum/multiple/accessors/multiple_accessor'
2
+ require 'simple_enum/multiple/accessors/join_table_accessor'
3
+ require 'simple_enum/multiple/accessors/bitwise_accessor'
4
+
5
+ module SimpleEnum
6
+ module Multiple
7
+ module Accessors
8
+ SimpleEnum::Accessors::ACCESSORS.merge!({
9
+ multiple: MultipleAccessor,
10
+ join_table: JoinTableAccessor,
11
+ bitwise: BitwiseAccessor
12
+ })
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,22 @@
1
+ module SimpleEnum
2
+ module Multiple
3
+ module Coders
4
+ class Bitwise
5
+ def self.load(data)
6
+ n = data.to_i
7
+ (0..Math.log2(n).floor).reject do |i|
8
+ (n & (1 << i)).zero?
9
+ end
10
+ rescue FloatDomainError, Math::DomainError
11
+ []
12
+ end
13
+
14
+ def self.dump(array)
15
+ array.map do |i|
16
+ 1 << i
17
+ end.reduce(&:+)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,30 @@
1
+ module SimpleEnum
2
+ module Multiple
3
+ class CollectionProxy
4
+ attr_reader :origin, :accessor
5
+
6
+ def initialize(origin, accessor)
7
+ @origin, @accessor = origin, accessor
8
+ end
9
+
10
+ def push(*keys)
11
+ keys = accessor.filter_keys(keys)
12
+ origin.push(*accessor.fetch_values(keys)).uniq!
13
+ self
14
+ end
15
+ alias_method :<<, :push
16
+
17
+ def delete(key)
18
+ origin.delete(accessor.enum.value(key)) && key
19
+ end
20
+
21
+ def proxy
22
+ accessor.fetch_keys(origin)
23
+ end
24
+
25
+ alias_method :to_a, :proxy
26
+ delegate :inspect, :to_s, :==, to: :proxy
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,11 @@
1
+ module SimpleEnum
2
+ module Multiple
3
+ module Extension
4
+ def generate_enum_multiple_extension_for enum, accessor
5
+ accessor.init(self) if accessor.respond_to? :init
6
+ end
7
+ end
8
+ end
9
+ end
10
+
11
+ SimpleEnum.register_generator :multiple, SimpleEnum::Multiple::Extension
@@ -0,0 +1,5 @@
1
+ module SimpleEnum
2
+ module Multiple
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,10 @@
1
+ require 'simple_enum/multiple/accessors'
2
+ require 'simple_enum/multiple/collection_proxy'
3
+ require 'simple_enum/multiple/extension'
4
+ require 'simple_enum/multiple/version'
5
+
6
+ module SimpleEnum
7
+ module Multiple
8
+ # Your code goes here...
9
+ end
10
+ end
@@ -0,0 +1,37 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'simple_enum/multiple/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "simple_enum-multiple"
8
+ spec.version = SimpleEnum::Multiple::VERSION
9
+ spec.authors = ["Theo"]
10
+ spec.email = ["bbtfrr@gmail.com"]
11
+
12
+ spec.summary = %q{Multi-select enum support for SimpleEnum.}
13
+ spec.description = %q{SimpleEnum::Multiple is extension of SimpleEnum, which brings multi-select enum support to SimpleEnum.}
14
+ spec.homepage = "https://github.com/bbtfr/simple_enum-multiple"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
18
+ # delete this section to allow pushing this gem to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
21
+ else
22
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
+ end
24
+
25
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_runtime_dependency 'simple_enum', '~> 2.2'
31
+
32
+ spec.add_development_dependency 'bundler', '~> 1.10'
33
+ spec.add_development_dependency 'rake', '~> 10.0'
34
+ spec.add_development_dependency 'activerecord', '>= 4.0.0'
35
+ spec.add_development_dependency 'mongoid', '>= 4.0.0'
36
+ spec.add_development_dependency 'rspec', '~> 2.14'
37
+ end
metadata ADDED
@@ -0,0 +1,147 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple_enum-multiple
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Theo
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-09-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: simple_enum
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.10'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.10'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activerecord
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 4.0.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 4.0.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: mongoid
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 4.0.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 4.0.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.14'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '2.14'
97
+ description: SimpleEnum::Multiple is extension of SimpleEnum, which brings multi-select
98
+ enum support to SimpleEnum.
99
+ email:
100
+ - bbtfrr@gmail.com
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - Gemfile
107
+ - LICENSE.txt
108
+ - README.md
109
+ - Rakefile
110
+ - bin/console
111
+ - bin/setup
112
+ - lib/simple_enum/multiple.rb
113
+ - lib/simple_enum/multiple/accessors.rb
114
+ - lib/simple_enum/multiple/accessors/bitwise_accessor.rb
115
+ - lib/simple_enum/multiple/accessors/join_table_accessor.rb
116
+ - lib/simple_enum/multiple/accessors/multiple_accessor.rb
117
+ - lib/simple_enum/multiple/coders/bitwise.rb
118
+ - lib/simple_enum/multiple/collection_proxy.rb
119
+ - lib/simple_enum/multiple/extension.rb
120
+ - lib/simple_enum/multiple/version.rb
121
+ - simple_enum-multiple.gemspec
122
+ homepage: https://github.com/bbtfr/simple_enum-multiple
123
+ licenses:
124
+ - MIT
125
+ metadata:
126
+ allowed_push_host: https://rubygems.org
127
+ post_install_message:
128
+ rdoc_options: []
129
+ require_paths:
130
+ - lib
131
+ required_ruby_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ required_rubygems_version: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ requirements: []
142
+ rubyforge_project:
143
+ rubygems_version: 2.4.6
144
+ signing_key:
145
+ specification_version: 4
146
+ summary: Multi-select enum support for SimpleEnum.
147
+ test_files: []