mini-fast-sys 0.0.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/mini-fast-sys.gemspec +12 -0
- data/ransack-4.4.1/LICENSE +20 -0
- data/ransack-4.4.1/README.md +101 -0
- data/ransack-4.4.1/lib/polyamorous/activerecord/join_association.rb +70 -0
- data/ransack-4.4.1/lib/polyamorous/activerecord/join_association_7_2.rb +55 -0
- data/ransack-4.4.1/lib/polyamorous/activerecord/join_dependency.rb +102 -0
- data/ransack-4.4.1/lib/polyamorous/activerecord/reflection.rb +11 -0
- data/ransack-4.4.1/lib/polyamorous/join.rb +70 -0
- data/ransack-4.4.1/lib/polyamorous/polyamorous.rb +27 -0
- data/ransack-4.4.1/lib/polyamorous/swapping_reflection_class.rb +11 -0
- data/ransack-4.4.1/lib/polyamorous/tree_node.rb +7 -0
- data/ransack-4.4.1/lib/ransack/active_record.rb +14 -0
- data/ransack-4.4.1/lib/ransack/adapters/active_record/base.rb +152 -0
- data/ransack-4.4.1/lib/ransack/adapters/active_record/context.rb +373 -0
- data/ransack-4.4.1/lib/ransack/configuration.rb +209 -0
- data/ransack-4.4.1/lib/ransack/constants.rb +176 -0
- data/ransack-4.4.1/lib/ransack/context.rb +190 -0
- data/ransack-4.4.1/lib/ransack/helpers/form_builder.rb +277 -0
- data/ransack-4.4.1/lib/ransack/helpers/form_helper.rb +311 -0
- data/ransack-4.4.1/lib/ransack/helpers.rb +2 -0
- data/ransack-4.4.1/lib/ransack/invalid_search_error.rb +3 -0
- data/ransack-4.4.1/lib/ransack/locale/ar.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/az.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/bg.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/ca.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/cs.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/da.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/de.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/el.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/en.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/es.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/fa.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/fi.yml +71 -0
- data/ransack-4.4.1/lib/ransack/locale/fr.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/hu.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/id.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/it.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/ja.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/ko.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/nl.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/pt-BR.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/ro.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/ru.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/sk.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/sv.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/tr.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/uk.yml +72 -0
- data/ransack-4.4.1/lib/ransack/locale/zh-CN.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/zh-TW.yml +70 -0
- data/ransack-4.4.1/lib/ransack/naming.rb +58 -0
- data/ransack-4.4.1/lib/ransack/nodes/attribute.rb +59 -0
- data/ransack-4.4.1/lib/ransack/nodes/bindable.rb +52 -0
- data/ransack-4.4.1/lib/ransack/nodes/condition.rb +399 -0
- data/ransack-4.4.1/lib/ransack/nodes/grouping.rb +206 -0
- data/ransack-4.4.1/lib/ransack/nodes/node.rb +34 -0
- data/ransack-4.4.1/lib/ransack/nodes/sort.rb +54 -0
- data/ransack-4.4.1/lib/ransack/nodes/value.rb +115 -0
- data/ransack-4.4.1/lib/ransack/predicate.rb +75 -0
- data/ransack-4.4.1/lib/ransack/ransacker.rb +24 -0
- data/ransack-4.4.1/lib/ransack/search.rb +195 -0
- data/ransack-4.4.1/lib/ransack/translate.rb +156 -0
- data/ransack-4.4.1/lib/ransack/version.rb +3 -0
- data/ransack-4.4.1/lib/ransack/visitor.rb +87 -0
- data/ransack-4.4.1/lib/ransack.rb +33 -0
- data/ransack-4.4.1/spec/console.rb +13 -0
- data/ransack-4.4.1/spec/factories/articles.rb +7 -0
- data/ransack-4.4.1/spec/factories/comments.rb +7 -0
- data/ransack-4.4.1/spec/factories/notes.rb +13 -0
- data/ransack-4.4.1/spec/factories/people.rb +10 -0
- data/ransack-4.4.1/spec/factories/tags.rb +5 -0
- data/ransack-4.4.1/spec/helpers/polyamorous_helper.rb +13 -0
- data/ransack-4.4.1/spec/helpers/ransack_helper.rb +9 -0
- data/ransack-4.4.1/spec/polyamorous/activerecord_compatibility_spec.rb +15 -0
- data/ransack-4.4.1/spec/polyamorous/join_association_spec.rb +29 -0
- data/ransack-4.4.1/spec/polyamorous/join_dependency_spec.rb +80 -0
- data/ransack-4.4.1/spec/polyamorous/join_spec.rb +19 -0
- data/ransack-4.4.1/spec/ransack/adapters/active_record/base_spec.rb +943 -0
- data/ransack-4.4.1/spec/ransack/adapters/active_record/context_spec.rb +219 -0
- data/ransack-4.4.1/spec/ransack/configuration_spec.rb +201 -0
- data/ransack-4.4.1/spec/ransack/helpers/form_builder_spec.rb +169 -0
- data/ransack-4.4.1/spec/ransack/helpers/form_helper_spec.rb +1075 -0
- data/ransack-4.4.1/spec/ransack/invalid_search_error_spec.rb +27 -0
- data/ransack-4.4.1/spec/ransack/nodes/condition_spec.rb +333 -0
- data/ransack-4.4.1/spec/ransack/nodes/grouping_spec.rb +111 -0
- data/ransack-4.4.1/spec/ransack/nodes/value_spec.rb +126 -0
- data/ransack-4.4.1/spec/ransack/predicate_spec.rb +504 -0
- data/ransack-4.4.1/spec/ransack/ransacker_spec.rb +69 -0
- data/ransack-4.4.1/spec/ransack/search_spec.rb +821 -0
- data/ransack-4.4.1/spec/ransack/translate_spec.rb +16 -0
- data/ransack-4.4.1/spec/spec_helper.rb +52 -0
- data/ransack-4.4.1/spec/support/en.yml +18 -0
- data/ransack-4.4.1/spec/support/schema.rb +419 -0
- metadata +133 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
module Ransack
|
|
2
|
+
module Nodes
|
|
3
|
+
class Value < Node
|
|
4
|
+
attr_accessor :value
|
|
5
|
+
delegate :present?, :blank?, to: :value
|
|
6
|
+
|
|
7
|
+
def initialize(context, value = nil)
|
|
8
|
+
super(context)
|
|
9
|
+
@value = value
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def persisted?
|
|
13
|
+
false
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def eql?(other)
|
|
17
|
+
self.class == other.class && self.value == other.value
|
|
18
|
+
end
|
|
19
|
+
alias :== :eql?
|
|
20
|
+
|
|
21
|
+
def hash
|
|
22
|
+
value.hash
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def cast(type)
|
|
26
|
+
case type
|
|
27
|
+
when :date
|
|
28
|
+
cast_to_date(value)
|
|
29
|
+
when :datetime, :timestamp, :time, :timestamptz
|
|
30
|
+
cast_to_time(value)
|
|
31
|
+
when :boolean
|
|
32
|
+
cast_to_boolean(value)
|
|
33
|
+
when :integer
|
|
34
|
+
cast_to_integer(value)
|
|
35
|
+
when :float
|
|
36
|
+
cast_to_float(value)
|
|
37
|
+
when :decimal
|
|
38
|
+
cast_to_decimal(value)
|
|
39
|
+
when :money
|
|
40
|
+
cast_to_money(value)
|
|
41
|
+
else
|
|
42
|
+
cast_to_string(value)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def cast_to_date(val)
|
|
47
|
+
if val.respond_to?(:to_date)
|
|
48
|
+
val.to_date rescue nil
|
|
49
|
+
else
|
|
50
|
+
y, m, d = *[val].flatten
|
|
51
|
+
m ||= 1
|
|
52
|
+
d ||= 1
|
|
53
|
+
Date.new(y, m, d) rescue nil
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def cast_to_time(val)
|
|
58
|
+
if val.is_a?(Array)
|
|
59
|
+
Time.zone.local(*val) rescue nil
|
|
60
|
+
else
|
|
61
|
+
unless val.acts_like?(:time)
|
|
62
|
+
val = val.is_a?(String) ? Time.zone.parse(val) : val.to_time rescue val
|
|
63
|
+
end
|
|
64
|
+
val.in_time_zone rescue nil
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def cast_to_boolean(val)
|
|
69
|
+
if Constants::TRUE_VALUES.include?(val)
|
|
70
|
+
true
|
|
71
|
+
elsif Constants::FALSE_VALUES.include?(val)
|
|
72
|
+
false
|
|
73
|
+
else
|
|
74
|
+
nil
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def cast_to_string(val)
|
|
79
|
+
val.respond_to?(:to_s) ? val.to_s : String.new(val)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def cast_to_integer(val)
|
|
83
|
+
val.respond_to?(:to_i) && !val.blank? ? val.to_i : nil
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def cast_to_float(val)
|
|
87
|
+
val.blank? ? nil : val.to_f
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def cast_to_decimal(val)
|
|
91
|
+
if val.blank?
|
|
92
|
+
nil
|
|
93
|
+
elsif val.class == BigDecimal
|
|
94
|
+
val
|
|
95
|
+
elsif val.respond_to?(:to_d)
|
|
96
|
+
val.to_d
|
|
97
|
+
else
|
|
98
|
+
val.to_s.to_d
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def cast_to_money(val)
|
|
103
|
+
val.blank? ? nil : val.to_f.to_s
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def inspect
|
|
107
|
+
"Value <#{value}>"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def array_of_arrays?(val)
|
|
111
|
+
Array === val && Array === val.first
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
module Ransack
|
|
2
|
+
class Predicate
|
|
3
|
+
attr_reader :name, :arel_predicate, :type, :formatter, :validator,
|
|
4
|
+
:compound, :wants_array, :case_insensitive
|
|
5
|
+
|
|
6
|
+
class << self
|
|
7
|
+
|
|
8
|
+
def names
|
|
9
|
+
Ransack.predicates.keys
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def named(name)
|
|
13
|
+
Ransack.predicates[(name || Ransack.options[:default_predicate]).to_s]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def detect_and_strip_from_string!(str)
|
|
17
|
+
detect_from_string str, chomp: true
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def detect_from_string(str, chomp: false)
|
|
21
|
+
return unless str
|
|
22
|
+
|
|
23
|
+
Ransack.predicates.sorted_names_with_underscores.each do |predicate, underscored|
|
|
24
|
+
if str.end_with? underscored
|
|
25
|
+
str.chomp! underscored if chomp
|
|
26
|
+
return predicate
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
nil
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def initialize(opts = {})
|
|
36
|
+
@name = opts[:name]
|
|
37
|
+
@arel_predicate = opts[:arel_predicate]
|
|
38
|
+
@type = opts[:type]
|
|
39
|
+
@formatter = opts[:formatter]
|
|
40
|
+
@validator = opts[:validator] ||
|
|
41
|
+
lambda { |v| v.respond_to?(:empty?) ? !v.empty? : !v.nil? }
|
|
42
|
+
@compound = opts[:compound]
|
|
43
|
+
@wants_array = opts.fetch(:wants_array,
|
|
44
|
+
@compound || Constants::IN_NOT_IN.include?(@arel_predicate))
|
|
45
|
+
@case_insensitive = opts[:case_insensitive]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def eql?(other)
|
|
49
|
+
self.class == other.class &&
|
|
50
|
+
self.name == other.name
|
|
51
|
+
end
|
|
52
|
+
alias :== :eql?
|
|
53
|
+
|
|
54
|
+
def hash
|
|
55
|
+
name.hash
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def format(val)
|
|
59
|
+
if formatter
|
|
60
|
+
formatter.call(val)
|
|
61
|
+
else
|
|
62
|
+
val
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def validate(vals, type = @type)
|
|
67
|
+
vals.any? { |v| validator.call(type ? v.cast(type) : v.value) }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def negative?
|
|
71
|
+
@name.include?("not_".freeze)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Ransack
|
|
2
|
+
class Ransacker
|
|
3
|
+
|
|
4
|
+
attr_reader :name, :type, :formatter, :args
|
|
5
|
+
|
|
6
|
+
delegate :call, to: :@callable
|
|
7
|
+
|
|
8
|
+
def initialize(klass, name, opts = {}, &block)
|
|
9
|
+
@klass, @name = klass, name
|
|
10
|
+
|
|
11
|
+
@type = opts[:type] || :string
|
|
12
|
+
@args = opts[:args] || [:parent]
|
|
13
|
+
@formatter = opts[:formatter]
|
|
14
|
+
@callable = opts[:callable] || block ||
|
|
15
|
+
(@klass.method(name) if @klass.respond_to?(name)) ||
|
|
16
|
+
proc { |parent| parent.table[name] }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def attr_from(bindable)
|
|
20
|
+
call(*args.map { |arg| bindable.send(arg) })
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
require 'ransack/nodes/bindable'
|
|
2
|
+
require 'ransack/nodes/node'
|
|
3
|
+
require 'ransack/nodes/attribute'
|
|
4
|
+
require 'ransack/nodes/value'
|
|
5
|
+
require 'ransack/nodes/condition'
|
|
6
|
+
require 'ransack/nodes/sort'
|
|
7
|
+
require 'ransack/nodes/grouping'
|
|
8
|
+
require 'ransack/context'
|
|
9
|
+
require 'ransack/naming'
|
|
10
|
+
require 'ransack/invalid_search_error'
|
|
11
|
+
|
|
12
|
+
module Ransack
|
|
13
|
+
class Search
|
|
14
|
+
include Naming
|
|
15
|
+
|
|
16
|
+
attr_reader :base, :context
|
|
17
|
+
|
|
18
|
+
delegate :object, :klass, to: :context
|
|
19
|
+
delegate :new_grouping, :new_condition,
|
|
20
|
+
:build_grouping, :build_condition,
|
|
21
|
+
:translate, to: :base
|
|
22
|
+
|
|
23
|
+
def initialize(object, params = {}, options = {})
|
|
24
|
+
strip_whitespace = options.fetch(:strip_whitespace, Ransack.options[:strip_whitespace])
|
|
25
|
+
params = params.to_unsafe_h if params.respond_to?(:to_unsafe_h)
|
|
26
|
+
if params.is_a? Hash
|
|
27
|
+
params = params.dup
|
|
28
|
+
params = params.transform_values { |v| v.is_a?(String) && strip_whitespace ? v.strip : v }
|
|
29
|
+
params.delete_if { |k, v| [*v].all?{ |i| i.blank? && i != false } }
|
|
30
|
+
else
|
|
31
|
+
params = {}
|
|
32
|
+
end
|
|
33
|
+
@context = options[:context] || Context.for(object, options)
|
|
34
|
+
@context.auth_object = options[:auth_object]
|
|
35
|
+
@base = Nodes::Grouping.new(
|
|
36
|
+
@context, options[:grouping] || Constants::AND
|
|
37
|
+
)
|
|
38
|
+
@scope_args = {}
|
|
39
|
+
@sorts ||= []
|
|
40
|
+
@ignore_unknown_conditions = options[:ignore_unknown_conditions] == false ? false : true
|
|
41
|
+
build(params.with_indifferent_access)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def result(opts = {})
|
|
45
|
+
@context.evaluate(self, opts)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def build(params)
|
|
49
|
+
collapse_multiparameter_attributes!(params).each do |key, value|
|
|
50
|
+
if ['s'.freeze, 'sorts'.freeze].freeze.include?(key)
|
|
51
|
+
send("#{key}=", value)
|
|
52
|
+
elsif @context.ransackable_scope?(key, @context.object)
|
|
53
|
+
add_scope(key, value)
|
|
54
|
+
elsif base.attribute_method?(key)
|
|
55
|
+
base.send("#{key}=", value)
|
|
56
|
+
elsif !Ransack.options[:ignore_unknown_conditions] || !@ignore_unknown_conditions
|
|
57
|
+
raise InvalidSearchError, "Invalid search term #{key}"
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
self
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def sorts=(args)
|
|
64
|
+
case args
|
|
65
|
+
when Array
|
|
66
|
+
args.each do |sort|
|
|
67
|
+
if sort.kind_of? Hash
|
|
68
|
+
sort = Nodes::Sort.new(@context).build(sort)
|
|
69
|
+
else
|
|
70
|
+
sort = Nodes::Sort.extract(@context, sort)
|
|
71
|
+
end
|
|
72
|
+
self.sorts << sort if sort
|
|
73
|
+
end
|
|
74
|
+
when Hash
|
|
75
|
+
args.each do |index, attrs|
|
|
76
|
+
sort = Nodes::Sort.new(@context).build(attrs)
|
|
77
|
+
self.sorts << sort
|
|
78
|
+
end
|
|
79
|
+
when String
|
|
80
|
+
self.sorts = [args]
|
|
81
|
+
else
|
|
82
|
+
raise InvalidSearchError,
|
|
83
|
+
"Invalid argument (#{args.class}) supplied to sorts="
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
alias :s= :sorts=
|
|
87
|
+
|
|
88
|
+
def sorts
|
|
89
|
+
@sorts
|
|
90
|
+
end
|
|
91
|
+
alias :s :sorts
|
|
92
|
+
|
|
93
|
+
def build_sort(opts = {})
|
|
94
|
+
new_sort(opts).tap do |sort|
|
|
95
|
+
self.sorts << sort
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def new_sort(opts = {})
|
|
100
|
+
Nodes::Sort.new(@context).build(opts)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def method_missing(method_id, *args)
|
|
104
|
+
method_name = method_id.to_s
|
|
105
|
+
getter_name = method_name.sub(/=$/, ''.freeze)
|
|
106
|
+
if base.attribute_method?(getter_name)
|
|
107
|
+
base.send(method_id, *args)
|
|
108
|
+
elsif @context.ransackable_scope?(getter_name, @context.object)
|
|
109
|
+
if method_name =~ /=$/
|
|
110
|
+
add_scope getter_name, args
|
|
111
|
+
else
|
|
112
|
+
@scope_args[method_name]
|
|
113
|
+
end
|
|
114
|
+
else
|
|
115
|
+
super
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def inspect
|
|
120
|
+
details = [
|
|
121
|
+
[:class, klass.name],
|
|
122
|
+
([:scope, @scope_args] if @scope_args.present?),
|
|
123
|
+
[:base, base.inspect]
|
|
124
|
+
]
|
|
125
|
+
.compact
|
|
126
|
+
.map { |d| d.join(': '.freeze) }
|
|
127
|
+
.join(', '.freeze)
|
|
128
|
+
|
|
129
|
+
"Ransack::Search<#{details}>"
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
private
|
|
133
|
+
|
|
134
|
+
def add_scope(key, args)
|
|
135
|
+
sanitized_args = if Ransack.options[:sanitize_scope_args] && !@context.ransackable_scope_skip_sanitize_args?(key, @context.object)
|
|
136
|
+
sanitized_scope_args(args)
|
|
137
|
+
else
|
|
138
|
+
args
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
if @context.scope_arity(key) == 1
|
|
142
|
+
@scope_args[key] = args.is_a?(Array) ? args[0] : args
|
|
143
|
+
else
|
|
144
|
+
@scope_args[key] = args.is_a?(Array) ? sanitized_args : args
|
|
145
|
+
end
|
|
146
|
+
@context.chain_scope(key, sanitized_args)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def sanitized_scope_args(args)
|
|
150
|
+
if args.is_a?(Array)
|
|
151
|
+
args = args.map(&method(:sanitized_scope_args))
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
if Constants::TRUE_VALUES.include? args
|
|
155
|
+
true
|
|
156
|
+
elsif Constants::FALSE_VALUES.include? args
|
|
157
|
+
false
|
|
158
|
+
else
|
|
159
|
+
args
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def collapse_multiparameter_attributes!(attrs)
|
|
164
|
+
attrs.keys.each do |k|
|
|
165
|
+
if k.include?(Constants::LEFT_PARENTHESIS)
|
|
166
|
+
real_attribute, position = k.split(/\(|\)/)
|
|
167
|
+
cast =
|
|
168
|
+
if Constants::A_S_I.include?(position.last)
|
|
169
|
+
position.last
|
|
170
|
+
else
|
|
171
|
+
nil
|
|
172
|
+
end
|
|
173
|
+
position = position.to_i - 1
|
|
174
|
+
value = attrs.delete(k)
|
|
175
|
+
attrs[real_attribute] ||= []
|
|
176
|
+
attrs[real_attribute][position] =
|
|
177
|
+
if cast
|
|
178
|
+
if value.blank? && cast == Constants::I
|
|
179
|
+
nil
|
|
180
|
+
else
|
|
181
|
+
value.send("to_#{cast}")
|
|
182
|
+
end
|
|
183
|
+
else
|
|
184
|
+
value
|
|
185
|
+
end
|
|
186
|
+
elsif Hash === attrs[k]
|
|
187
|
+
collapse_multiparameter_attributes!(attrs[k])
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
attrs
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
end
|
|
195
|
+
end
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
require 'i18n'
|
|
2
|
+
|
|
3
|
+
I18n.load_path += Dir[
|
|
4
|
+
File.join(File.dirname(__FILE__), 'locale'.freeze, '*.yml'.freeze)
|
|
5
|
+
]
|
|
6
|
+
|
|
7
|
+
module Ransack
|
|
8
|
+
module Translate
|
|
9
|
+
class << self
|
|
10
|
+
def word(key, options = {})
|
|
11
|
+
I18n.translate(:"ransack.#{key}", default: key.to_s)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def predicate(key, options = {})
|
|
15
|
+
I18n.translate(:"ransack.predicates.#{key}", default: key.to_s)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def attribute(key, options = {})
|
|
19
|
+
unless context = options.delete(:context)
|
|
20
|
+
raise ArgumentError, "A context is required to translate attributes"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
original_name = key.to_s
|
|
24
|
+
base_class = context.klass
|
|
25
|
+
base_ancestors = base_class.ancestors.select {
|
|
26
|
+
|x| x.respond_to?(:model_name)
|
|
27
|
+
}
|
|
28
|
+
attributes_str = original_name.dup # will be modified by ⬇
|
|
29
|
+
predicate = Predicate.detect_and_strip_from_string!(attributes_str)
|
|
30
|
+
attribute_names = attributes_str.split(/_and_|_or_/)
|
|
31
|
+
combinator = attributes_str =~ /_and_/ ? :and : :or
|
|
32
|
+
defaults = base_ancestors.map do |klass|
|
|
33
|
+
"ransack.attributes.#{i18n_key(klass)}.#{original_name}".to_sym
|
|
34
|
+
end
|
|
35
|
+
defaults << options.delete(:default) if options[:default]
|
|
36
|
+
|
|
37
|
+
translated_names = attribute_names.map do |name|
|
|
38
|
+
attribute_name(context, name, options[:include_associations])
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
interpolations = {
|
|
42
|
+
attributes: translated_names.join(" #{Translate.word(combinator)} ")
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if predicate
|
|
46
|
+
defaults << "%{attributes} %{predicate}".freeze
|
|
47
|
+
interpolations[:predicate] = Translate.predicate(predicate)
|
|
48
|
+
else
|
|
49
|
+
defaults << "%{attributes}".freeze
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
options.reverse_merge! count: 1, default: defaults
|
|
53
|
+
I18n.translate(defaults.shift, **options.merge(interpolations))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def association(key, options = {})
|
|
57
|
+
unless context = options.delete(:context)
|
|
58
|
+
raise ArgumentError, "A context is required to translate associations"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
defaults =
|
|
62
|
+
if key.blank?
|
|
63
|
+
[:"ransack.models.#{i18n_key(context.klass)}",
|
|
64
|
+
:"#{context.klass.i18n_scope}.models.#{i18n_key(context.klass)}"]
|
|
65
|
+
else
|
|
66
|
+
[:"ransack.associations.#{i18n_key(context.klass)}.#{key}"]
|
|
67
|
+
end
|
|
68
|
+
defaults << context.traverse(key).model_name.human
|
|
69
|
+
options = { count: 1, default: defaults }
|
|
70
|
+
I18n.translate(defaults.shift, **options)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
def attribute_name(context, name, include_associations = nil)
|
|
76
|
+
@context, @name = context, name
|
|
77
|
+
@assoc_path = context.association_path(name)
|
|
78
|
+
@attr_name = @name.sub(/^#{@assoc_path}_/, ''.freeze)
|
|
79
|
+
associated_class = @context.traverse(@assoc_path) if @assoc_path.present?
|
|
80
|
+
@include_associated = include_associations && associated_class
|
|
81
|
+
|
|
82
|
+
defaults = default_attribute_name << fallback_args
|
|
83
|
+
options = { count: 1, default: defaults }
|
|
84
|
+
interpolations = build_interpolations(associated_class)
|
|
85
|
+
|
|
86
|
+
I18n.translate(defaults.shift, **options.merge(interpolations))
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def default_attribute_name
|
|
90
|
+
["ransack.attributes.#{i18n_key(@context.klass)}.#{@name}".to_sym]
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def fallback_args
|
|
94
|
+
if @include_associated
|
|
95
|
+
'%{association_name} %{attr_fallback_name}'.freeze
|
|
96
|
+
else
|
|
97
|
+
'%{attr_fallback_name}'.freeze
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def build_interpolations(associated_class)
|
|
102
|
+
{
|
|
103
|
+
attr_fallback_name: attr_fallback_name(associated_class),
|
|
104
|
+
association_name: association_name
|
|
105
|
+
}.reject { |_, value| value.nil? }
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def attr_fallback_name(associated_class)
|
|
109
|
+
I18n.t(
|
|
110
|
+
:"ransack.attributes.#{fallback_class(associated_class)}.#{@attr_name}",
|
|
111
|
+
default: default_interpolation(associated_class)
|
|
112
|
+
)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def fallback_class(associated_class)
|
|
116
|
+
i18n_key(associated_class || @context.klass)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def association_name
|
|
120
|
+
association(@assoc_path, context: @context) if @include_associated
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def default_interpolation(associated_class)
|
|
124
|
+
[
|
|
125
|
+
associated_attribute(associated_class),
|
|
126
|
+
".attributes.#{@attr_name}".to_sym,
|
|
127
|
+
@attr_name.humanize
|
|
128
|
+
].flatten
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def associated_attribute(associated_class)
|
|
132
|
+
if associated_class
|
|
133
|
+
translated_attribute(associated_class)
|
|
134
|
+
else
|
|
135
|
+
translated_ancestor_attributes
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def translated_attribute(associated_class)
|
|
140
|
+
key = "#{associated_class.i18n_scope}.attributes.#{
|
|
141
|
+
i18n_key(associated_class)}.#{@attr_name}"
|
|
142
|
+
["#{key}.one".to_sym, key.to_sym]
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def translated_ancestor_attributes
|
|
146
|
+
@context.klass.ancestors
|
|
147
|
+
.select { |ancestor| ancestor.respond_to?(:model_name) }
|
|
148
|
+
.map { |ancestor| translated_attribute(ancestor) }
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def i18n_key(klass)
|
|
152
|
+
klass.model_name.i18n_key
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
module Ransack
|
|
2
|
+
class Visitor
|
|
3
|
+
|
|
4
|
+
def accept(object)
|
|
5
|
+
visit(object)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def can_accept?(object)
|
|
9
|
+
respond_to? DISPATCH[object.class]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def visit_Array(object)
|
|
13
|
+
object.map { |o| accept(o) }.compact
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def visit_Ransack_Nodes_Condition(object)
|
|
17
|
+
object.arel_predicate if object.valid?
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def visit_Ransack_Nodes_Grouping(object)
|
|
21
|
+
if object.combinator == Constants::OR
|
|
22
|
+
visit_or(object)
|
|
23
|
+
else
|
|
24
|
+
visit_and(object)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def visit_and(object)
|
|
29
|
+
nodes = object.values.map { |o| accept(o) }.compact
|
|
30
|
+
return nil unless nodes.size > 0
|
|
31
|
+
|
|
32
|
+
if nodes.size > 1
|
|
33
|
+
Arel::Nodes::Grouping.new(Arel::Nodes::And.new(nodes))
|
|
34
|
+
else
|
|
35
|
+
nodes.first
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def visit_or(object)
|
|
40
|
+
nodes = object.values.map { |o| accept(o) }.compact
|
|
41
|
+
nodes.inject(&:or)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def quoted?(object)
|
|
45
|
+
case object
|
|
46
|
+
when Arel::Nodes::SqlLiteral, Bignum, Fixnum
|
|
47
|
+
false
|
|
48
|
+
else
|
|
49
|
+
true
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def visit(object)
|
|
54
|
+
send(DISPATCH[object.class], object)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def visit_Ransack_Nodes_Sort(object)
|
|
58
|
+
if object.valid?
|
|
59
|
+
if object.attr.is_a?(Arel::Attributes::Attribute)
|
|
60
|
+
object.attr.send(object.dir)
|
|
61
|
+
else
|
|
62
|
+
ordered(object)
|
|
63
|
+
end
|
|
64
|
+
else
|
|
65
|
+
scope_name = :"sort_by_#{object.name}_#{object.dir}"
|
|
66
|
+
scope_name if object.context.object.respond_to?(scope_name)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
DISPATCH = Hash.new do |hash, klass|
|
|
71
|
+
hash[klass] = "visit_#{
|
|
72
|
+
klass.name.gsub(Constants::TWO_COLONS, Constants::UNDERSCORE)
|
|
73
|
+
}"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def ordered(object)
|
|
79
|
+
case object.dir
|
|
80
|
+
when 'asc'.freeze
|
|
81
|
+
Arel::Nodes::Ascending.new(object.attr)
|
|
82
|
+
when 'desc'.freeze
|
|
83
|
+
Arel::Nodes::Descending.new(object.attr)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'active_support/dependencies/autoload'
|
|
2
|
+
require 'active_support/deprecation'
|
|
3
|
+
require 'active_support/deprecator'
|
|
4
|
+
|
|
5
|
+
require 'active_support/core_ext'
|
|
6
|
+
require 'ransack/configuration'
|
|
7
|
+
require 'polyamorous/polyamorous'
|
|
8
|
+
|
|
9
|
+
module Ransack
|
|
10
|
+
extend Configuration
|
|
11
|
+
class UntraversableAssociationError < StandardError; end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
Ransack.configure do |config|
|
|
15
|
+
Ransack::Constants::AREL_PREDICATES.each do |name|
|
|
16
|
+
config.add_predicate name, arel_predicate: name
|
|
17
|
+
end
|
|
18
|
+
Ransack::Constants::DERIVED_PREDICATES.each do |args|
|
|
19
|
+
config.add_predicate(*args)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
require 'ransack/search'
|
|
24
|
+
require 'ransack/ransacker'
|
|
25
|
+
require 'ransack/translate'
|
|
26
|
+
require 'ransack/active_record'
|
|
27
|
+
require 'ransack/context'
|
|
28
|
+
require 'ransack/version'
|
|
29
|
+
|
|
30
|
+
ActiveSupport.on_load(:action_controller) do
|
|
31
|
+
require 'ransack/helpers'
|
|
32
|
+
ActionController::Base.helper Ransack::Helpers::FormHelper
|
|
33
|
+
end
|