scopiform 0.1.1
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +42 -0
- data/Rakefile +27 -0
- data/lib/scopiform/association_scopes.rb +61 -0
- data/lib/scopiform/common_scopes.rb +47 -0
- data/lib/scopiform/core.rb +62 -0
- data/lib/scopiform/filters.rb +40 -0
- data/lib/scopiform/helpers.rb +69 -0
- data/lib/scopiform/reflection_plugin.rb +9 -0
- data/lib/scopiform/scope_definition.rb +16 -0
- data/lib/scopiform/string_number_date_scopes.rb +70 -0
- data/lib/scopiform/string_number_scopes.rb +80 -0
- data/lib/scopiform/version.rb +3 -0
- data/lib/scopiform.rb +24 -0
- data/lib/tasks/scopiform_tasks.rake +4 -0
- metadata +100 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 394c2b67ce4035049ec008ebb55628c2ccff5b37f7bed36d3dee01b3ed16d7bf
|
4
|
+
data.tar.gz: 4e08965af4db81bd6694c999ab3718f1ad81bcfceebbcbb3f666e4faaf7eaef5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7f412f41367de72362799423196deeb247926941e0d710faa4e94bd41f9af79b76182c52d0ba90f9b7366fb65c192848bbf94fe22ceede2bf5644b59f567b576
|
7
|
+
data.tar.gz: e955b4a42b3f4aea8ea456424e6b54e637cc8592448024a0c31ddf277acb7a219d1ab7577645aeff20dc1fd2892239fa4c674907f21adf02a0755f0164a9394d
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2020 jayce.pulsipher
|
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,42 @@
|
|
1
|
+
# Scopiform
|
2
|
+
Short description and motivation.
|
3
|
+
|
4
|
+
## Usage
|
5
|
+
How to use my plugin.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'scopiform'
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
```bash
|
16
|
+
$ bundle
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
```bash
|
21
|
+
$ gem install scopiform
|
22
|
+
```
|
23
|
+
|
24
|
+
## Public ActiveRecord Methods
|
25
|
+
:aliases_for
|
26
|
+
:apply_filters
|
27
|
+
:apply_orders
|
28
|
+
:association
|
29
|
+
:attribute_aliases_inverted
|
30
|
+
:auto_scope_add
|
31
|
+
:auto_scope?
|
32
|
+
:auto_scopes_by_attribute
|
33
|
+
:auto_scopes
|
34
|
+
:column
|
35
|
+
:reflection_added
|
36
|
+
:resolve_alias
|
37
|
+
|
38
|
+
## Contributing
|
39
|
+
Contribution directions go here.
|
40
|
+
|
41
|
+
## License
|
42
|
+
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,27 @@
|
|
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 = 'Scopiform'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'bundler/gem_tasks'
|
18
|
+
|
19
|
+
require 'rake/testtask'
|
20
|
+
|
21
|
+
Rake::TestTask.new(:test) do |t|
|
22
|
+
t.libs << 'test'
|
23
|
+
t.pattern = 'test/**/*_test.rb'
|
24
|
+
t.verbose = false
|
25
|
+
end
|
26
|
+
|
27
|
+
task default: :test
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/concern'
|
4
|
+
|
5
|
+
module Scopiform
|
6
|
+
module AssociationScopes
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
setup_associations_auto_scopes
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def reflection_added(_name, reflection)
|
15
|
+
setup_association_auto_scopes(reflection)
|
16
|
+
end
|
17
|
+
|
18
|
+
def scopiform_joins(*args, **kargs)
|
19
|
+
respond_to?(:left_outer_joins) ? left_outer_joins(*args, **kargs) : eager_load(*args, **kargs)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def setup_associations_auto_scopes
|
25
|
+
reflect_on_all_associations.each do |association|
|
26
|
+
setup_association_auto_scopes(association)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def setup_association_auto_scopes(association)
|
31
|
+
auto_scope_add(
|
32
|
+
association.name,
|
33
|
+
Proc.new { |value, joins: nil|
|
34
|
+
is_root = joins.nil?
|
35
|
+
joins = {} if is_root
|
36
|
+
|
37
|
+
joins[association.name] ||= {}
|
38
|
+
applied = association.klass.apply_filters(value, joins: joins[association.name])
|
39
|
+
|
40
|
+
if is_root
|
41
|
+
scopiform_joins(joins).merge(applied)
|
42
|
+
else
|
43
|
+
all.merge(applied)
|
44
|
+
end
|
45
|
+
},
|
46
|
+
suffix: '_is',
|
47
|
+
argument_type: :hash
|
48
|
+
)
|
49
|
+
|
50
|
+
# Ordering
|
51
|
+
auto_scope_add(
|
52
|
+
association.name,
|
53
|
+
Proc.new { |value| scopiform_joins(association.name).merge(association.klass.apply_orders(value)) },
|
54
|
+
prefix: 'order_by_',
|
55
|
+
argument_type: :hash,
|
56
|
+
type: :order
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/concern'
|
4
|
+
|
5
|
+
module Scopiform
|
6
|
+
module CommonScopes
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
setup_common_auto_scopes
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
private
|
15
|
+
|
16
|
+
def setup_common_auto_scopes
|
17
|
+
safe_columns.each do |column|
|
18
|
+
name = column.name
|
19
|
+
name_sym = name.to_sym
|
20
|
+
type = column.type
|
21
|
+
|
22
|
+
auto_scope_add(
|
23
|
+
name,
|
24
|
+
Proc.new { |value| where(name_sym => value) },
|
25
|
+
suffix: '_is',
|
26
|
+
argument_type: type
|
27
|
+
)
|
28
|
+
auto_scope_add(
|
29
|
+
name,
|
30
|
+
Proc.new { |value| where.not(name_sym => value) },
|
31
|
+
suffix: '_not',
|
32
|
+
argument_type: type
|
33
|
+
)
|
34
|
+
|
35
|
+
# Ordering
|
36
|
+
auto_scope_add(
|
37
|
+
name,
|
38
|
+
->(value = :asc) { order(name_sym => value) },
|
39
|
+
prefix: 'order_by_',
|
40
|
+
argument_type: :string,
|
41
|
+
type: :order
|
42
|
+
)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/concern'
|
4
|
+
require 'scopiform/scope_definition'
|
5
|
+
|
6
|
+
module Scopiform
|
7
|
+
module Core
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def auto_scopes
|
12
|
+
@auto_scopes || []
|
13
|
+
end
|
14
|
+
|
15
|
+
def auto_scopes_by_attribute(attribute)
|
16
|
+
attribute = attribute.to_sym
|
17
|
+
auto_scopes.select { |scope| scope.attribute == attribute }
|
18
|
+
end
|
19
|
+
|
20
|
+
def auto_scope?(name)
|
21
|
+
auto_scopes.find { |scope| scope.name == name }
|
22
|
+
end
|
23
|
+
|
24
|
+
def auto_scope_add(attribute, block, prefix: nil, suffix: nil, **options)
|
25
|
+
scope_name = "#{prefix}#{attribute}#{suffix}".underscore
|
26
|
+
scope_name_sym = scope_name.to_sym
|
27
|
+
scope scope_name_sym, block
|
28
|
+
|
29
|
+
scope_definition = auto_scope_add_definition(attribute, prefix: prefix, suffix: suffix, **options)
|
30
|
+
|
31
|
+
aliases_for(attribute).each do |alias_name|
|
32
|
+
auto_scope_for_alias(alias_name, scope_definition)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def alias_attribute(new_name, old_name)
|
37
|
+
super(new_name, old_name)
|
38
|
+
|
39
|
+
auto_scopes_by_attribute(old_name).each do |scope_definition|
|
40
|
+
auto_scope_for_alias(new_name, scope_definition)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def auto_scope_add_definition(attribute, **options)
|
47
|
+
definition = ScopeDefinition.new(attribute, **options)
|
48
|
+
@auto_scopes ||= []
|
49
|
+
@auto_scopes << definition
|
50
|
+
|
51
|
+
definition
|
52
|
+
end
|
53
|
+
|
54
|
+
def auto_scope_for_alias(alias_name, scope_definition)
|
55
|
+
scope_name = "#{scope_definition.prefix}#{scope_definition.attribute}#{scope_definition.suffix}".underscore
|
56
|
+
alias_method_name = "#{scope_definition.prefix}#{alias_name}#{scope_definition.suffix}".underscore
|
57
|
+
singleton_class.send(:alias_method, alias_method_name.to_sym, scope_name.to_sym)
|
58
|
+
auto_scope_add_definition(alias_name, prefix: scope_definition.prefix, suffix: scope_definition.suffix, **scope_definition.options)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/concern'
|
4
|
+
|
5
|
+
module Scopiform
|
6
|
+
module Filters
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def apply_filters(filters_hash, injecting: all, joins: nil)
|
11
|
+
filters_hash.keys.inject(injecting) { |out, filter_name| resolve_filter(out, filter_name, filters_hash[filter_name], joins) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def apply_orders(orders_hash, injecting = all)
|
15
|
+
orders_hash.keys.inject(injecting) { |out, order_name| resolve_order(out, order_name, orders_hash[order_name]) }
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def resolve_filter(out, filter_name, filter_argument, joins)
|
21
|
+
if filter_name.to_s.casecmp('OR').zero?
|
22
|
+
or_joins = {}
|
23
|
+
|
24
|
+
return (
|
25
|
+
filter_argument
|
26
|
+
.map { |or_filters_hash| apply_filters(or_filters_hash, injecting: out, joins: or_joins) }
|
27
|
+
.map { |a| a.scopiform_joins(or_joins) }
|
28
|
+
.inject { |chain, applied| chain.or(applied) }
|
29
|
+
)
|
30
|
+
end
|
31
|
+
out.send(filter_name, filter_argument, joins: joins)
|
32
|
+
end
|
33
|
+
|
34
|
+
def resolve_order(out, order_name, order_argument)
|
35
|
+
method_name = "order_by_#{order_name}"
|
36
|
+
out.send(method_name, order_argument)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/concern'
|
4
|
+
|
5
|
+
module Scopiform
|
6
|
+
module Helpers
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
STRING_TYPES = %i[string text].freeze
|
10
|
+
NUMBER_TYPES = %i[integer float decimal].freeze
|
11
|
+
DATE_TYPES = %i[date time datetime timestamp].freeze
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def attribute_aliases
|
15
|
+
alias_hash = super
|
16
|
+
|
17
|
+
key = primary_key.to_s
|
18
|
+
alias_hash = alias_hash.merge('id' => key) if key != 'id'
|
19
|
+
|
20
|
+
alias_hash
|
21
|
+
end
|
22
|
+
|
23
|
+
def attribute_aliases_inverted
|
24
|
+
attribute_aliases.each_with_object({}) { |(k, v), o| (o[v] ||= []) << k }
|
25
|
+
end
|
26
|
+
|
27
|
+
def resolve_alias(name)
|
28
|
+
name_str = name.to_s
|
29
|
+
return attribute_aliases[name_str] if attribute_aliases[name_str].present?
|
30
|
+
|
31
|
+
name_str
|
32
|
+
end
|
33
|
+
|
34
|
+
def aliases_for(name)
|
35
|
+
attribute_aliases_inverted[name.to_s] || []
|
36
|
+
end
|
37
|
+
|
38
|
+
def column(name)
|
39
|
+
name = resolve_alias(name)
|
40
|
+
safe_columns_hash[name.to_s]
|
41
|
+
end
|
42
|
+
|
43
|
+
def association(name)
|
44
|
+
name = resolve_alias(name)
|
45
|
+
association = reflect_on_association(name)
|
46
|
+
|
47
|
+
association.klass if association.present?
|
48
|
+
association
|
49
|
+
rescue NameError
|
50
|
+
logger.warn "Unable to load class for association `#{name}` in model `#{self.name}`"
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
|
54
|
+
protected
|
55
|
+
|
56
|
+
def safe_columns
|
57
|
+
columns
|
58
|
+
rescue ActiveRecord::StatementInvalid, Mysql::Error, Mysql2::Error
|
59
|
+
[]
|
60
|
+
end
|
61
|
+
|
62
|
+
def safe_columns_hash
|
63
|
+
columns_hash
|
64
|
+
rescue ActiveRecord::StatementInvalid, Mysql::Error, Mysql2::Error
|
65
|
+
{}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Scopiform
|
2
|
+
class ScopeDefinition
|
3
|
+
attr_accessor :attribute, :prefix, :suffix, :options
|
4
|
+
|
5
|
+
def initialize(attribute, prefix: nil, suffix: nil, **options)
|
6
|
+
@attribute = attribute.to_sym
|
7
|
+
@prefix = prefix
|
8
|
+
@suffix = suffix
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def name
|
13
|
+
"#{prefix}#{attribute}#{suffix}".underscore
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/concern'
|
4
|
+
|
5
|
+
module Scopiform
|
6
|
+
module StringNumberDateScopes
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
setup_string_number_and_date_auto_scopes
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
private
|
15
|
+
|
16
|
+
def setup_string_number_and_date_auto_scopes
|
17
|
+
string_number_dates = Helpers::STRING_TYPES + Helpers::NUMBER_TYPES + Helpers::DATE_TYPES
|
18
|
+
string_number_date_columns = safe_columns.select { |column| string_number_dates.include? column.type }
|
19
|
+
string_number_date_columns.each do |column|
|
20
|
+
name = column.name
|
21
|
+
name_sym = name.to_sym
|
22
|
+
type = column.type
|
23
|
+
arel_column = arel_table[name]
|
24
|
+
|
25
|
+
auto_scope_add(
|
26
|
+
name,
|
27
|
+
Proc.new { |value| where(name_sym => value) },
|
28
|
+
suffix: '_in',
|
29
|
+
argument_type: [type]
|
30
|
+
)
|
31
|
+
|
32
|
+
auto_scope_add(
|
33
|
+
name,
|
34
|
+
Proc.new { |value| where.not(name_sym => value) },
|
35
|
+
suffix: '_not_in',
|
36
|
+
argument_type: [type]
|
37
|
+
)
|
38
|
+
|
39
|
+
auto_scope_add(
|
40
|
+
name,
|
41
|
+
Proc.new { |value| where(arel_column.lt(value)) },
|
42
|
+
suffix: '_lt',
|
43
|
+
argument_type: type
|
44
|
+
)
|
45
|
+
|
46
|
+
auto_scope_add(
|
47
|
+
name,
|
48
|
+
Proc.new { |value| where(arel_column.lteq(value)) },
|
49
|
+
suffix: '_lte',
|
50
|
+
argument_type: type
|
51
|
+
)
|
52
|
+
|
53
|
+
auto_scope_add(
|
54
|
+
name,
|
55
|
+
Proc.new { |value| where(arel_column.gt(value)) },
|
56
|
+
suffix: '_gt',
|
57
|
+
argument_type: type
|
58
|
+
)
|
59
|
+
|
60
|
+
auto_scope_add(
|
61
|
+
name,
|
62
|
+
Proc.new { |value| where(arel_column.gteq(value)) },
|
63
|
+
suffix: '_gte',
|
64
|
+
argument_type: type
|
65
|
+
)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/concern'
|
4
|
+
|
5
|
+
module Scopiform
|
6
|
+
module StringNumberScopes
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
setup_string_and_number_auto_scopes
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
private
|
15
|
+
|
16
|
+
def setup_string_and_number_auto_scopes
|
17
|
+
string_numbers = Helpers::STRING_TYPES + Helpers::NUMBER_TYPES
|
18
|
+
string_number_columns = safe_columns.select { |column| string_numbers.include? column.type }
|
19
|
+
string_number_columns.each do |column|
|
20
|
+
name = column.name
|
21
|
+
type = column.type
|
22
|
+
arel_column = arel_table[name]
|
23
|
+
|
24
|
+
# Numeric values don't work properly with `.matches`. Using workaround
|
25
|
+
# https://coderwall.com/p/qtgvdq/using-arel_table-for-ilike-yes-even-with-integers
|
26
|
+
if Helpers::NUMBER_TYPES.include? column.type
|
27
|
+
arel_column = Arel::Nodes::NamedFunction.new(
|
28
|
+
'CAST',
|
29
|
+
[arel_column.as('TEXT')]
|
30
|
+
)
|
31
|
+
|
32
|
+
type = :string
|
33
|
+
end
|
34
|
+
|
35
|
+
auto_scope_add(
|
36
|
+
name,
|
37
|
+
Proc.new { |value| where(arel_column.matches("%#{ActiveRecord::Base.sanitize_sql_like(value.to_s)}%")) },
|
38
|
+
suffix: '_contains',
|
39
|
+
type: type
|
40
|
+
)
|
41
|
+
|
42
|
+
auto_scope_add(
|
43
|
+
name,
|
44
|
+
Proc.new { |value| where.not(arel_column.matches("%#{ActiveRecord::Base.sanitize_sql_like(value.to_s)}%")) },
|
45
|
+
suffix: '_not_contains',
|
46
|
+
type: type
|
47
|
+
)
|
48
|
+
|
49
|
+
auto_scope_add(
|
50
|
+
name,
|
51
|
+
Proc.new { |value| where(arel_column.matches("#{ActiveRecord::Base.sanitize_sql_like(value.to_s)}%")) },
|
52
|
+
suffix: '_starts_with',
|
53
|
+
type: type
|
54
|
+
)
|
55
|
+
|
56
|
+
auto_scope_add(
|
57
|
+
name,
|
58
|
+
Proc.new { |value| where.not(arel_column.matches("#{ActiveRecord::Base.sanitize_sql_like(value.to_s)}%")) },
|
59
|
+
suffix: '_not_starts_with',
|
60
|
+
type: type
|
61
|
+
)
|
62
|
+
|
63
|
+
auto_scope_add(
|
64
|
+
name,
|
65
|
+
Proc.new { |value| where(arel_column.matches("%#{ActiveRecord::Base.sanitize_sql_like(value.to_s)}")) },
|
66
|
+
suffix: '_ends_with',
|
67
|
+
type: type
|
68
|
+
)
|
69
|
+
|
70
|
+
auto_scope_add(
|
71
|
+
name,
|
72
|
+
Proc.new { |value| where.not(arel_column.matches("%#{ActiveRecord::Base.sanitize_sql_like(value.to_s)}")) },
|
73
|
+
suffix: '_not_ends_with',
|
74
|
+
type: type
|
75
|
+
)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/scopiform.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'scopiform/helpers'
|
2
|
+
require 'scopiform/core'
|
3
|
+
require 'scopiform/common_scopes'
|
4
|
+
require 'scopiform/string_number_scopes'
|
5
|
+
require 'scopiform/string_number_date_scopes'
|
6
|
+
require 'scopiform/association_scopes'
|
7
|
+
require 'scopiform/reflection_plugin'
|
8
|
+
require 'scopiform/filters'
|
9
|
+
|
10
|
+
module Scopiform
|
11
|
+
def self.included(base)
|
12
|
+
base.class_eval do
|
13
|
+
include Scopiform::Helpers
|
14
|
+
include Scopiform::Core
|
15
|
+
include Scopiform::CommonScopes
|
16
|
+
include Scopiform::StringNumberScopes
|
17
|
+
include Scopiform::StringNumberDateScopes
|
18
|
+
include Scopiform::AssociationScopes
|
19
|
+
include Scopiform::Filters
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
ActiveRecord::Reflection.singleton_class.prepend Scopiform::ReflectionPlugin
|
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: scopiform
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- jayce.pulsipher
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-03-13 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: 4.2.7
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 4.2.7
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rails_or
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.1'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sqlite3
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- jayce.pulsipher@3-form.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- MIT-LICENSE
|
63
|
+
- README.md
|
64
|
+
- Rakefile
|
65
|
+
- lib/scopiform.rb
|
66
|
+
- lib/scopiform/association_scopes.rb
|
67
|
+
- lib/scopiform/common_scopes.rb
|
68
|
+
- lib/scopiform/core.rb
|
69
|
+
- lib/scopiform/filters.rb
|
70
|
+
- lib/scopiform/helpers.rb
|
71
|
+
- lib/scopiform/reflection_plugin.rb
|
72
|
+
- lib/scopiform/scope_definition.rb
|
73
|
+
- lib/scopiform/string_number_date_scopes.rb
|
74
|
+
- lib/scopiform/string_number_scopes.rb
|
75
|
+
- lib/scopiform/version.rb
|
76
|
+
- lib/tasks/scopiform_tasks.rake
|
77
|
+
homepage: https://github.com/3-form/scopiform
|
78
|
+
licenses:
|
79
|
+
- MIT
|
80
|
+
metadata: {}
|
81
|
+
post_install_message:
|
82
|
+
rdoc_options: []
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
requirements: []
|
96
|
+
rubygems_version: 3.0.3
|
97
|
+
signing_key:
|
98
|
+
specification_version: 4
|
99
|
+
summary: Generate scope methods to ActiveRecord classes based on columns and associations
|
100
|
+
test_files: []
|