giga-pure-kit 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.

Potentially problematic release.


This version of giga-pure-kit might be problematic. Click here for more details.

Files changed (94) hide show
  1. checksums.yaml +7 -0
  2. data/giga-pure-kit.gemspec +12 -0
  3. data/ransack-4.4.1/LICENSE +20 -0
  4. data/ransack-4.4.1/README.md +101 -0
  5. data/ransack-4.4.1/lib/polyamorous/activerecord/join_association.rb +218 -0
  6. data/ransack-4.4.1/lib/polyamorous/activerecord/join_association_7_2.rb +55 -0
  7. data/ransack-4.4.1/lib/polyamorous/activerecord/join_dependency.rb +102 -0
  8. data/ransack-4.4.1/lib/polyamorous/activerecord/reflection.rb +11 -0
  9. data/ransack-4.4.1/lib/polyamorous/join.rb +70 -0
  10. data/ransack-4.4.1/lib/polyamorous/polyamorous.rb +27 -0
  11. data/ransack-4.4.1/lib/polyamorous/swapping_reflection_class.rb +11 -0
  12. data/ransack-4.4.1/lib/polyamorous/tree_node.rb +7 -0
  13. data/ransack-4.4.1/lib/ransack/active_record.rb +14 -0
  14. data/ransack-4.4.1/lib/ransack/adapters/active_record/base.rb +152 -0
  15. data/ransack-4.4.1/lib/ransack/adapters/active_record/context.rb +373 -0
  16. data/ransack-4.4.1/lib/ransack/configuration.rb +209 -0
  17. data/ransack-4.4.1/lib/ransack/constants.rb +176 -0
  18. data/ransack-4.4.1/lib/ransack/context.rb +190 -0
  19. data/ransack-4.4.1/lib/ransack/helpers/form_builder.rb +277 -0
  20. data/ransack-4.4.1/lib/ransack/helpers/form_helper.rb +311 -0
  21. data/ransack-4.4.1/lib/ransack/helpers.rb +2 -0
  22. data/ransack-4.4.1/lib/ransack/invalid_search_error.rb +3 -0
  23. data/ransack-4.4.1/lib/ransack/locale/ar.yml +70 -0
  24. data/ransack-4.4.1/lib/ransack/locale/az.yml +70 -0
  25. data/ransack-4.4.1/lib/ransack/locale/bg.yml +70 -0
  26. data/ransack-4.4.1/lib/ransack/locale/ca.yml +70 -0
  27. data/ransack-4.4.1/lib/ransack/locale/cs.yml +70 -0
  28. data/ransack-4.4.1/lib/ransack/locale/da.yml +70 -0
  29. data/ransack-4.4.1/lib/ransack/locale/de.yml +70 -0
  30. data/ransack-4.4.1/lib/ransack/locale/el.yml +70 -0
  31. data/ransack-4.4.1/lib/ransack/locale/en.yml +70 -0
  32. data/ransack-4.4.1/lib/ransack/locale/es.yml +70 -0
  33. data/ransack-4.4.1/lib/ransack/locale/fa.yml +70 -0
  34. data/ransack-4.4.1/lib/ransack/locale/fi.yml +71 -0
  35. data/ransack-4.4.1/lib/ransack/locale/fr.yml +70 -0
  36. data/ransack-4.4.1/lib/ransack/locale/hu.yml +70 -0
  37. data/ransack-4.4.1/lib/ransack/locale/id.yml +70 -0
  38. data/ransack-4.4.1/lib/ransack/locale/it.yml +70 -0
  39. data/ransack-4.4.1/lib/ransack/locale/ja.yml +70 -0
  40. data/ransack-4.4.1/lib/ransack/locale/ko.yml +70 -0
  41. data/ransack-4.4.1/lib/ransack/locale/nl.yml +70 -0
  42. data/ransack-4.4.1/lib/ransack/locale/pt-BR.yml +70 -0
  43. data/ransack-4.4.1/lib/ransack/locale/ro.yml +70 -0
  44. data/ransack-4.4.1/lib/ransack/locale/ru.yml +70 -0
  45. data/ransack-4.4.1/lib/ransack/locale/sk.yml +70 -0
  46. data/ransack-4.4.1/lib/ransack/locale/sv.yml +70 -0
  47. data/ransack-4.4.1/lib/ransack/locale/tr.yml +70 -0
  48. data/ransack-4.4.1/lib/ransack/locale/uk.yml +72 -0
  49. data/ransack-4.4.1/lib/ransack/locale/zh-CN.yml +70 -0
  50. data/ransack-4.4.1/lib/ransack/locale/zh-TW.yml +70 -0
  51. data/ransack-4.4.1/lib/ransack/naming.rb +58 -0
  52. data/ransack-4.4.1/lib/ransack/nodes/attribute.rb +59 -0
  53. data/ransack-4.4.1/lib/ransack/nodes/bindable.rb +52 -0
  54. data/ransack-4.4.1/lib/ransack/nodes/condition.rb +399 -0
  55. data/ransack-4.4.1/lib/ransack/nodes/grouping.rb +206 -0
  56. data/ransack-4.4.1/lib/ransack/nodes/node.rb +34 -0
  57. data/ransack-4.4.1/lib/ransack/nodes/sort.rb +54 -0
  58. data/ransack-4.4.1/lib/ransack/nodes/value.rb +115 -0
  59. data/ransack-4.4.1/lib/ransack/predicate.rb +75 -0
  60. data/ransack-4.4.1/lib/ransack/ransacker.rb +24 -0
  61. data/ransack-4.4.1/lib/ransack/search.rb +195 -0
  62. data/ransack-4.4.1/lib/ransack/translate.rb +156 -0
  63. data/ransack-4.4.1/lib/ransack/version.rb +3 -0
  64. data/ransack-4.4.1/lib/ransack/visitor.rb +87 -0
  65. data/ransack-4.4.1/lib/ransack.rb +33 -0
  66. data/ransack-4.4.1/spec/console.rb +13 -0
  67. data/ransack-4.4.1/spec/factories/articles.rb +7 -0
  68. data/ransack-4.4.1/spec/factories/comments.rb +7 -0
  69. data/ransack-4.4.1/spec/factories/notes.rb +13 -0
  70. data/ransack-4.4.1/spec/factories/people.rb +10 -0
  71. data/ransack-4.4.1/spec/factories/tags.rb +5 -0
  72. data/ransack-4.4.1/spec/helpers/polyamorous_helper.rb +13 -0
  73. data/ransack-4.4.1/spec/helpers/ransack_helper.rb +9 -0
  74. data/ransack-4.4.1/spec/polyamorous/activerecord_compatibility_spec.rb +15 -0
  75. data/ransack-4.4.1/spec/polyamorous/join_association_spec.rb +29 -0
  76. data/ransack-4.4.1/spec/polyamorous/join_dependency_spec.rb +80 -0
  77. data/ransack-4.4.1/spec/polyamorous/join_spec.rb +19 -0
  78. data/ransack-4.4.1/spec/ransack/adapters/active_record/base_spec.rb +943 -0
  79. data/ransack-4.4.1/spec/ransack/adapters/active_record/context_spec.rb +219 -0
  80. data/ransack-4.4.1/spec/ransack/configuration_spec.rb +201 -0
  81. data/ransack-4.4.1/spec/ransack/helpers/form_builder_spec.rb +169 -0
  82. data/ransack-4.4.1/spec/ransack/helpers/form_helper_spec.rb +1075 -0
  83. data/ransack-4.4.1/spec/ransack/invalid_search_error_spec.rb +27 -0
  84. data/ransack-4.4.1/spec/ransack/nodes/condition_spec.rb +333 -0
  85. data/ransack-4.4.1/spec/ransack/nodes/grouping_spec.rb +111 -0
  86. data/ransack-4.4.1/spec/ransack/nodes/value_spec.rb +126 -0
  87. data/ransack-4.4.1/spec/ransack/predicate_spec.rb +504 -0
  88. data/ransack-4.4.1/spec/ransack/ransacker_spec.rb +69 -0
  89. data/ransack-4.4.1/spec/ransack/search_spec.rb +821 -0
  90. data/ransack-4.4.1/spec/ransack/translate_spec.rb +16 -0
  91. data/ransack-4.4.1/spec/spec_helper.rb +52 -0
  92. data/ransack-4.4.1/spec/support/en.yml +18 -0
  93. data/ransack-4.4.1/spec/support/schema.rb +419 -0
  94. metadata +133 -0
@@ -0,0 +1,206 @@
1
+ module Ransack
2
+ module Nodes
3
+ class Grouping < Node
4
+ attr_reader :conditions
5
+ attr_accessor :combinator
6
+ alias :m :combinator
7
+ alias :m= :combinator=
8
+
9
+ i18n_word :condition, :and, :or
10
+ i18n_alias c: :condition, n: :and, o: :or
11
+
12
+ delegate :each, to: :values
13
+
14
+ def initialize(context, combinator = nil)
15
+ super(context)
16
+ self.combinator = combinator.to_s if combinator
17
+ end
18
+
19
+ def persisted?
20
+ false
21
+ end
22
+
23
+ def translate(key, options = {})
24
+ super or Translate.attribute(
25
+ key.to_s, options.merge(context: context)
26
+ )
27
+ end
28
+
29
+ def conditions
30
+ @conditions ||= []
31
+ end
32
+ alias :c :conditions
33
+
34
+ def conditions=(conditions)
35
+ case conditions
36
+ when Array
37
+ conditions.each do |attrs|
38
+ condition = Condition.new(@context).build(attrs)
39
+ self.conditions << condition if condition.valid?
40
+ end
41
+ when Hash
42
+ conditions.each do |index, attrs|
43
+ condition = Condition.new(@context).build(attrs)
44
+ self.conditions << condition if condition.valid?
45
+ end
46
+ end
47
+ remove_duplicate_conditions!
48
+ end
49
+ alias :c= :conditions=
50
+
51
+ def [](key)
52
+ conditions.detect { |c| c.key == key.to_s }
53
+ end
54
+
55
+ def []=(key, value)
56
+ conditions.reject! { |c| c.key == key.to_s && c&.value == value&.value }
57
+ self.conditions << value
58
+ end
59
+
60
+ def values
61
+ conditions + groupings
62
+ end
63
+
64
+ def respond_to?(method_id)
65
+ super or begin
66
+ method_name = method_id.to_s
67
+ attribute_method?(method_name) ? true : false
68
+ end
69
+ end
70
+
71
+ def build_condition(opts = {})
72
+ new_condition(opts).tap do |condition|
73
+ self.conditions << condition
74
+ end
75
+ end
76
+
77
+ def new_condition(opts = {})
78
+ attrs = opts[:attributes] || 1
79
+ vals = opts[:values] || 1
80
+ condition = Condition.new(@context)
81
+ attrs.times { condition.build_attribute }
82
+ vals.times { condition.build_value }
83
+ condition
84
+ end
85
+
86
+ def groupings
87
+ @groupings ||= []
88
+ end
89
+ alias :g :groupings
90
+
91
+ def groupings=(groupings)
92
+ case groupings
93
+ when Array
94
+ groupings.each do |attrs|
95
+ grouping_object = new_grouping(attrs)
96
+ self.groupings << grouping_object if grouping_object.values.any?
97
+ end
98
+ when Hash
99
+ groupings.each do |index, attrs|
100
+ grouping_object = new_grouping(attrs)
101
+ self.groupings << grouping_object if grouping_object.values.any?
102
+ end
103
+ else
104
+ raise ArgumentError,
105
+ "Invalid argument (#{groupings.class}) supplied to groupings="
106
+ end
107
+ end
108
+ alias :g= :groupings=
109
+
110
+ def method_missing(method_id, *args)
111
+ method_name = method_id.to_s.dup
112
+ writer = method_name.sub!(/\=$/, ''.freeze)
113
+ if attribute_method?(method_name)
114
+ if writer
115
+ write_attribute(method_name, *args)
116
+ else
117
+ read_attribute(method_name)
118
+ end
119
+ else
120
+ super
121
+ end
122
+ end
123
+
124
+ def attribute_method?(name)
125
+ stripped_name = strip_predicate_and_index(name)
126
+ return true if @context.attribute_method?(stripped_name) ||
127
+ @context.attribute_method?(name)
128
+ case stripped_name
129
+ when /^(g|c|m|groupings|conditions|combinator)=?$/
130
+ true
131
+ else
132
+ stripped_name
133
+ .split(/_and_|_or_/)
134
+ .none? { |n| !@context.attribute_method?(n) }
135
+ end
136
+ end
137
+
138
+ def build_grouping(params = {})
139
+ params ||= {}
140
+ new_grouping(params).tap do |new_grouping|
141
+ self.groupings << new_grouping
142
+ end
143
+ end
144
+
145
+ def new_grouping(params = {})
146
+ Grouping.new(@context).build(params)
147
+ end
148
+
149
+ def build(params)
150
+ params.with_indifferent_access.each do |key, value|
151
+ case key
152
+ when /^(g|c|m)$/
153
+ self.send("#{key}=", value)
154
+ else
155
+ write_attribute(key.to_s, value)
156
+ end
157
+ end
158
+ self
159
+ end
160
+
161
+ def inspect
162
+ data = [
163
+ ['conditions'.freeze, conditions], [Constants::COMBINATOR, combinator]
164
+ ]
165
+ .reject { |e| e[1].blank? }
166
+ .map { |v| "#{v[0]}: #{v[1]}" }
167
+ .join(', '.freeze)
168
+ "Grouping <#{data}>"
169
+ end
170
+
171
+ private
172
+
173
+ def write_attribute(name, val)
174
+ # TODO: Methods
175
+ if condition = Condition.extract(@context, name, val)
176
+ self[name] = condition
177
+ end
178
+ end
179
+
180
+ def read_attribute(name)
181
+ if self[name].respond_to?(:value)
182
+ self[name].value
183
+ else
184
+ self[name]
185
+ end
186
+ end
187
+
188
+ def strip_predicate_and_index(str)
189
+ string = str[/(.+?)\(/, 1] || str.dup
190
+ Predicate.detect_and_strip_from_string!(string)
191
+ string
192
+ end
193
+
194
+ def remove_duplicate_conditions!
195
+ # If self.conditions.uniq! is called without passing a block, then
196
+ # conditions differing only by ransacker_args within attributes are
197
+ # wrongly considered equal and are removed.
198
+ self.conditions.uniq! do |c|
199
+ c.attributes.map { |a| [a.name, a.ransacker_args] }.flatten +
200
+ [c.predicate.name] +
201
+ c.values.map { |v| v.value }
202
+ end
203
+ end
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,34 @@
1
+ module Ransack
2
+ module Nodes
3
+ class Node
4
+ attr_reader :context
5
+ delegate :contextualize, to: :context
6
+ class_attribute :i18n_words
7
+ class_attribute :i18n_aliases
8
+ self.i18n_words = []
9
+ self.i18n_aliases = {}
10
+
11
+ class << self
12
+ def i18n_word(*args)
13
+ self.i18n_words += args.map(&:to_s)
14
+ end
15
+
16
+ def i18n_alias(opts = {})
17
+ self.i18n_aliases.merge! Hash[opts.map { |k, v| [k.to_s, v.to_s] }]
18
+ end
19
+ end
20
+
21
+ def initialize(context)
22
+ @context = context
23
+ end
24
+
25
+ def translate(key, options = {})
26
+ key = i18n_aliases[key.to_s] if i18n_aliases.has_key?(key.to_s)
27
+ if i18n_words.include?(key.to_s)
28
+ Translate.word(key)
29
+ end
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,54 @@
1
+ module Ransack
2
+ module Nodes
3
+ class Sort < Node
4
+ include Bindable
5
+
6
+ attr_reader :name, :dir, :ransacker_args
7
+ i18n_word :asc, :desc
8
+
9
+ class << self
10
+ def extract(context, str)
11
+ return if str.blank?
12
+ attr, direction = str.split(/\s+/, 2)
13
+ self.new(context).build(name: attr, dir: direction)
14
+ end
15
+ end
16
+
17
+ def build(params)
18
+ params.with_indifferent_access.each do |key, value|
19
+ if key.match(/^(name|dir|ransacker_args)$/)
20
+ self.send("#{key}=", value)
21
+ end
22
+ end
23
+
24
+ self
25
+ end
26
+
27
+ def valid?
28
+ bound? && attr &&
29
+ context.klassify(parent).ransortable_attributes(context.auth_object)
30
+ .include?(attr_name)
31
+ end
32
+
33
+ def name=(name)
34
+ @name = context.ransackable_alias(name) || name
35
+ context.bind(self, @name)
36
+ end
37
+
38
+ def dir=(dir)
39
+ dir = dir.downcase if dir
40
+ @dir =
41
+ if dir == 'asc'.freeze || dir == 'desc'.freeze
42
+ dir
43
+ else
44
+ 'asc'.freeze
45
+ end
46
+ end
47
+
48
+ def ransacker_args=(ransack_args)
49
+ @ransacker_args = ransack_args
50
+ end
51
+
52
+ end
53
+ end
54
+ end
@@ -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