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.
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,209 @@
1
+ require 'ransack/constants'
2
+ require 'ransack/predicate'
3
+
4
+ module Ransack
5
+ module Configuration
6
+
7
+ mattr_accessor :predicates, :options
8
+
9
+ class PredicateCollection
10
+ attr_reader :sorted_names_with_underscores
11
+
12
+ def initialize
13
+ @collection = {}
14
+ @sorted_names_with_underscores = []
15
+ end
16
+
17
+ delegate :[], :keys, :has_key?, to: :@collection
18
+
19
+ def []=(key, value)
20
+ @sorted_names_with_underscores << [key, '_' + key]
21
+ @sorted_names_with_underscores.sort! { |(a, _), (b, _)| b.length <=> a.length }
22
+
23
+ @collection[key] = value
24
+ end
25
+ end
26
+
27
+ self.predicates = PredicateCollection.new
28
+
29
+ self.options = {
30
+ search_key: :q,
31
+ ignore_unknown_conditions: true,
32
+ hide_sort_order_indicators: false,
33
+ up_arrow: '&#9660;'.freeze,
34
+ down_arrow: '&#9650;'.freeze,
35
+ default_arrow: nil,
36
+ sanitize_scope_args: true,
37
+ postgres_fields_sort_option: nil,
38
+ strip_whitespace: true
39
+ }
40
+
41
+ def configure
42
+ yield self
43
+ end
44
+
45
+ def add_predicate(name, opts = {})
46
+ name = name.to_s
47
+ opts[:name] = name
48
+ compounds = opts.delete(:compounds)
49
+ compounds = true if compounds.nil?
50
+ compounds = false if opts[:wants_array]
51
+
52
+ self.predicates[name] = Predicate.new(opts)
53
+
54
+ Constants::SUFFIXES.each do |suffix|
55
+ compound_name = name + suffix
56
+ self.predicates[compound_name] = Predicate.new(
57
+ opts.merge(
58
+ name: compound_name,
59
+ arel_predicate: arel_predicate_with_suffix(
60
+ opts[:arel_predicate], suffix
61
+ ),
62
+ compound: true
63
+ )
64
+ )
65
+ end if compounds
66
+ end
67
+
68
+ # The default `search_key` name is `:q`. The default key may be overridden
69
+ # in an initializer file like `config/initializers/ransack.rb` as follows:
70
+ #
71
+ # Ransack.configure do |config|
72
+ # # Name the search_key `:query` instead of the default `:q`
73
+ # config.search_key = :query
74
+ # end
75
+ #
76
+ # Sometimes there are situations when the default search parameter name
77
+ # cannot be used, for instance if there were two searches on one page.
78
+ # Another name can be set using the `search_key` option with Ransack
79
+ # `ransack`, `search` and `@search_form_for` methods in controllers & views.
80
+ #
81
+ # In the controller:
82
+ # @search = Log.ransack(params[:log_search], search_key: :log_search)
83
+ #
84
+ # In the view:
85
+ # <%= f.search_form_for @search, as: :log_search %>
86
+ #
87
+ def search_key=(name)
88
+ self.options[:search_key] = name
89
+ end
90
+
91
+ # By default Ransack ignores errors if an unknown predicate, condition or
92
+ # attribute is passed into a search. The default may be overridden in an
93
+ # initializer file like `config/initializers/ransack.rb` as follows:
94
+ #
95
+ # Ransack.configure do |config|
96
+ # # Raise if an unknown predicate, condition or attribute is passed
97
+ # config.ignore_unknown_conditions = false
98
+ # end
99
+ #
100
+ def ignore_unknown_conditions=(boolean)
101
+ self.options[:ignore_unknown_conditions] = boolean
102
+ end
103
+
104
+ # By default Ransack ignores empty predicates. Ransack can also fallback to
105
+ # a default predicate by setting it in an initializer file
106
+ # like `config/initializers/ransack.rb` as follows:
107
+ #
108
+ # Ransack.configure do |config|
109
+ # # Use the 'eq' predicate if an unknown predicate is passed
110
+ # config.default_predicate = 'eq'
111
+ # end
112
+ #
113
+ def default_predicate=(name)
114
+ self.options[:default_predicate] = name
115
+ end
116
+
117
+ # By default, Ransack displays sort order indicator arrows with HTML codes:
118
+ #
119
+ # up_arrow: '&#9660;'
120
+ # down_arrow: '&#9650;'
121
+ #
122
+ # There is also a default arrow which is displayed if a column is not sorted.
123
+ # By default this is nil so nothing will be displayed.
124
+ #
125
+ # Any of the defaults may be globally overridden in an initializer file
126
+ # like `config/initializers/ransack.rb` as follows:
127
+ #
128
+ # Ransack.configure do |config|
129
+ # # Globally set the up arrow to an icon, and the down and default arrows to unicode.
130
+ # config.custom_arrows = {
131
+ # up_arrow: '<i class="fa fa-long-arrow-up"></i>',
132
+ # down_arrow: 'U+02193',
133
+ # default_arrow: 'U+11047'
134
+ # }
135
+ # end
136
+ #
137
+ def custom_arrows=(opts = {})
138
+ self.options[:up_arrow] = opts[:up_arrow].freeze if opts[:up_arrow]
139
+ self.options[:down_arrow] = opts[:down_arrow].freeze if opts[:down_arrow]
140
+ self.options[:default_arrow] = opts[:default_arrow].freeze if opts[:default_arrow]
141
+ end
142
+
143
+ # Ransack sanitizes many values in your custom scopes into booleans.
144
+ # [1, '1', 't', 'T', 'true', 'TRUE'] all evaluate to true.
145
+ # [0, '0', 'f', 'F', 'false', 'FALSE'] all evaluate to false.
146
+ #
147
+ # This default may be globally overridden in an initializer file like
148
+ # `config/initializers/ransack.rb` as follows:
149
+ #
150
+ # Ransack.configure do |config|
151
+ # # Accept my custom scope values as what they are.
152
+ # config.sanitize_custom_scope_booleans = false
153
+ # end
154
+ #
155
+ def sanitize_custom_scope_booleans=(boolean)
156
+ self.options[:sanitize_scope_args] = boolean
157
+ end
158
+
159
+ # The `NULLS FIRST` and `NULLS LAST` options can be used to determine
160
+ # whether nulls appear before or after non-null values in the sort ordering.
161
+ #
162
+ # User may want to configure it like this:
163
+ #
164
+ # Ransack.configure do |c|
165
+ # c.postgres_fields_sort_option = :nulls_first # or e.g. :nulls_always_last
166
+ # end
167
+ #
168
+ # See this feature: https://www.postgresql.org/docs/13/queries-order.html
169
+ #
170
+ def postgres_fields_sort_option=(setting)
171
+ self.options[:postgres_fields_sort_option] = setting
172
+ end
173
+
174
+ # By default, Ransack displays sort order indicator arrows in sort links.
175
+ # The default may be globally overridden in an initializer file like
176
+ # `config/initializers/ransack.rb` as follows:
177
+ #
178
+ # Ransack.configure do |config|
179
+ # # Hide sort link order indicators globally across the application
180
+ # config.hide_sort_order_indicators = true
181
+ # end
182
+ #
183
+ def hide_sort_order_indicators=(boolean)
184
+ self.options[:hide_sort_order_indicators] = boolean
185
+ end
186
+
187
+ # By default, Ransack displays strips all whitespace when searching for a string.
188
+ # The default may be globally changed in an initializer file like
189
+ # `config/initializers/ransack.rb` as follows:
190
+ #
191
+ # Ransack.configure do |config|
192
+ # # Enable whitespace stripping for string searches
193
+ # config.strip_whitespace = true
194
+ # end
195
+ #
196
+ def strip_whitespace=(boolean)
197
+ self.options[:strip_whitespace] = boolean
198
+ end
199
+
200
+ def arel_predicate_with_suffix(arel_predicate, suffix)
201
+ if arel_predicate === Proc
202
+ proc { |v| "#{arel_predicate.call(v)}#{suffix}" }
203
+ else
204
+ "#{arel_predicate}#{suffix}"
205
+ end
206
+ end
207
+
208
+ end
209
+ end
@@ -0,0 +1,176 @@
1
+ module Ransack
2
+ module Constants
3
+ OR = 'or'.freeze
4
+ AND = 'and'.freeze
5
+
6
+ CAP_SEARCH = 'Search'.freeze
7
+ SEARCH = 'search'.freeze
8
+ SEARCHES = 'searches'.freeze
9
+
10
+ ATTRIBUTE = 'attribute'.freeze
11
+ ATTRIBUTES = 'attributes'.freeze
12
+ COMBINATOR = 'combinator'.freeze
13
+
14
+ TWO_COLONS = '::'.freeze
15
+ UNDERSCORE = '_'.freeze
16
+ LEFT_PARENTHESIS = '('.freeze
17
+ Q = 'q'.freeze
18
+ I = 'i'.freeze
19
+ DOT_ASTERIX = '.*'.freeze
20
+
21
+ STRING_JOIN = 'string_join'.freeze
22
+ ASSOCIATION_JOIN = 'association_join'.freeze
23
+ STASHED_JOIN = 'stashed_join'.freeze
24
+ JOIN_NODE = 'join_node'.freeze
25
+
26
+ TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE'].to_set
27
+ FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE'].to_set
28
+ BOOLEAN_VALUES = (TRUE_VALUES + FALSE_VALUES).freeze
29
+
30
+ AND_OR = ['and'.freeze, 'or'.freeze].freeze
31
+ IN_NOT_IN = ['in'.freeze, 'not_in'.freeze].freeze
32
+ SUFFIXES = ['_any'.freeze, '_all'.freeze].freeze
33
+ AREL_PREDICATES = [
34
+ 'eq'.freeze, 'not_eq'.freeze,
35
+ 'matches'.freeze, 'does_not_match'.freeze,
36
+ 'lt'.freeze, 'lteq'.freeze,
37
+ 'gt'.freeze, 'gteq'.freeze,
38
+ 'in'.freeze, 'not_in'.freeze
39
+ ].freeze
40
+ A_S_I = ['a'.freeze, 's'.freeze, 'i'.freeze].freeze
41
+
42
+ EQ = 'eq'.freeze
43
+ NOT_EQ = 'not_eq'.freeze
44
+ EQ_ANY = 'eq_any'.freeze
45
+ NOT_EQ_ALL = 'not_eq_all'.freeze
46
+ CONT = 'cont'.freeze
47
+
48
+ RANSACK_SLASH_SEARCHES = 'ransack/searches'.freeze
49
+ RANSACK_SLASH_SEARCHES_SLASH_SEARCH = 'ransack/searches/search'.freeze
50
+
51
+ DISTINCT = 'DISTINCT '.freeze
52
+
53
+ DERIVED_PREDICATES = [
54
+ [CONT, {
55
+ arel_predicate: 'matches'.freeze,
56
+ formatter: proc { |v| "%#{escape_wildcards(v)}%" }
57
+ }
58
+ ],
59
+ ['not_cont'.freeze, {
60
+ arel_predicate: 'does_not_match'.freeze,
61
+ formatter: proc { |v| "%#{escape_wildcards(v)}%" }
62
+ }
63
+ ],
64
+ ['i_cont'.freeze, {
65
+ arel_predicate: 'matches'.freeze,
66
+ formatter: proc { |v| "%#{escape_wildcards(v.downcase)}%" },
67
+ case_insensitive: true
68
+ }
69
+ ],
70
+ ['not_i_cont'.freeze, {
71
+ arel_predicate: 'does_not_match'.freeze,
72
+ formatter: proc { |v| "%#{escape_wildcards(v.downcase)}%" },
73
+ case_insensitive: true
74
+ }
75
+ ],
76
+ ['start'.freeze, {
77
+ arel_predicate: 'matches'.freeze,
78
+ formatter: proc { |v| "#{escape_wildcards(v)}%" }
79
+ }
80
+ ],
81
+ ['not_start'.freeze, {
82
+ arel_predicate: 'does_not_match'.freeze,
83
+ formatter: proc { |v| "#{escape_wildcards(v)}%" }
84
+ }
85
+ ],
86
+ ['end'.freeze, {
87
+ arel_predicate: 'matches'.freeze,
88
+ formatter: proc { |v| "%#{escape_wildcards(v)}" }
89
+ }
90
+ ],
91
+ ['not_end'.freeze, {
92
+ arel_predicate: 'does_not_match'.freeze,
93
+ formatter: proc { |v| "%#{escape_wildcards(v)}" }
94
+ }
95
+ ],
96
+ ['true'.freeze, {
97
+ arel_predicate: proc { |v| v ? EQ : NOT_EQ },
98
+ compounds: false,
99
+ type: :boolean,
100
+ validator: proc { |v| BOOLEAN_VALUES.include?(v) },
101
+ formatter: proc { |v| true }
102
+ }
103
+ ],
104
+ ['not_true'.freeze, {
105
+ arel_predicate: proc { |v| v ? NOT_EQ : EQ },
106
+ compounds: false,
107
+ type: :boolean,
108
+ validator: proc { |v| BOOLEAN_VALUES.include?(v) },
109
+ formatter: proc { |v| true }
110
+ }
111
+ ],
112
+ ['false'.freeze, {
113
+ arel_predicate: proc { |v| v ? EQ : NOT_EQ },
114
+ compounds: false,
115
+ type: :boolean,
116
+ validator: proc { |v| BOOLEAN_VALUES.include?(v) },
117
+ formatter: proc { |v| false }
118
+ }
119
+ ],
120
+ ['not_false'.freeze, {
121
+ arel_predicate: proc { |v| v ? NOT_EQ : EQ },
122
+ compounds: false,
123
+ type: :boolean,
124
+ validator: proc { |v| BOOLEAN_VALUES.include?(v) },
125
+ formatter: proc { |v| false }
126
+ }
127
+ ],
128
+ ['present'.freeze, {
129
+ arel_predicate: proc { |v| v ? NOT_EQ_ALL : EQ_ANY },
130
+ compounds: false,
131
+ type: :boolean,
132
+ validator: proc { |v| BOOLEAN_VALUES.include?(v) },
133
+ formatter: proc { |v| [nil, ''.freeze].freeze }
134
+ }
135
+ ],
136
+ ['blank'.freeze, {
137
+ arel_predicate: proc { |v| v ? EQ_ANY : NOT_EQ_ALL },
138
+ compounds: false,
139
+ type: :boolean,
140
+ validator: proc { |v| BOOLEAN_VALUES.include?(v) },
141
+ formatter: proc { |v| [nil, ''.freeze].freeze }
142
+ }
143
+ ],
144
+ ['null'.freeze, {
145
+ arel_predicate: proc { |v| v ? EQ : NOT_EQ },
146
+ compounds: false,
147
+ type: :boolean,
148
+ validator: proc { |v| BOOLEAN_VALUES.include?(v) },
149
+ formatter: proc { |v| nil }
150
+ }
151
+ ],
152
+ ['not_null'.freeze, {
153
+ arel_predicate: proc { |v| v ? NOT_EQ : EQ },
154
+ compounds: false,
155
+ type: :boolean,
156
+ validator: proc { |v| BOOLEAN_VALUES.include?(v) },
157
+ formatter: proc { |v| nil } }
158
+ ]
159
+ ].freeze
160
+
161
+ module_function
162
+ # replace % \ to \% \\
163
+ def escape_wildcards(unescaped)
164
+ case ActiveRecord::Base.connection.adapter_name
165
+ when "Mysql2".freeze
166
+ # Necessary for MySQL
167
+ unescaped.to_s.gsub(/([\\%_])/, '\\\\\\1')
168
+ when "PostGIS".freeze, "PostgreSQL".freeze
169
+ # Necessary for PostgreSQL
170
+ unescaped.to_s.gsub(/([\\%_.])/, '\\\\\\1')
171
+ else
172
+ unescaped
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,190 @@
1
+ require 'ransack/visitor'
2
+
3
+ module Ransack
4
+ class Context
5
+ attr_reader :search, :object, :klass, :base, :engine, :arel_visitor
6
+ attr_accessor :auth_object, :search_key
7
+ attr_reader :arel_visitor
8
+
9
+ class << self
10
+
11
+ def for_class(klass, options = {})
12
+ if klass < ActiveRecord::Base
13
+ Adapters::ActiveRecord::Context.new(klass, options)
14
+ end
15
+ end
16
+
17
+ def for_object(object, options = {})
18
+ case object
19
+ when ActiveRecord::Relation
20
+ Adapters::ActiveRecord::Context.new(object.klass, options)
21
+ end
22
+ end
23
+
24
+ def for(object, options = {})
25
+ context =
26
+ if Class === object
27
+ for_class(object, options)
28
+ else
29
+ for_object(object, options)
30
+ end
31
+ context or raise ArgumentError,
32
+ "Don't know what context to use for #{object}"
33
+ end
34
+
35
+ end # << self
36
+
37
+ def initialize(object, options = {})
38
+ @object = relation_for(object)
39
+ @klass = @object.klass
40
+ @join_dependency = join_dependency(@object)
41
+ @join_type = options[:join_type] || Polyamorous::OuterJoin
42
+ @search_key = options[:search_key] || Ransack.options[:search_key]
43
+ @associations_pot = {}
44
+ @tables_pot = {}
45
+ @lock_associations = []
46
+
47
+ @base = @join_dependency.instance_variable_get(:@join_root)
48
+ end
49
+
50
+ def bind_pair_for(key)
51
+ @bind_pairs ||= {}
52
+
53
+ @bind_pairs[key] ||= begin
54
+ parent, attr_name = get_parent_and_attribute_name(key.to_s)
55
+ [parent, attr_name] if parent && attr_name
56
+ end
57
+ end
58
+
59
+ def klassify(obj)
60
+ if Class === obj && ::ActiveRecord::Base > obj
61
+ obj
62
+ elsif obj.respond_to? :klass
63
+ obj.klass
64
+ else
65
+ raise ArgumentError, "Don't know how to klassify #{obj.inspect}"
66
+ end
67
+ end
68
+
69
+ # Convert a string representing a chain of associations and an attribute
70
+ # into the attribute itself
71
+ def contextualize(str)
72
+ parent, attr_name = bind_pair_for(str)
73
+ table_for(parent)[attr_name]
74
+ end
75
+
76
+ def chain_scope(scope, args)
77
+ return unless @klass.method(scope) && args != false
78
+ @object = if scope_arity(scope) < 1 && args == true
79
+ @object.public_send(scope)
80
+ elsif scope_arity(scope) == 1 && args.is_a?(Array)
81
+ # For scopes with arity 1, pass the array as a single argument instead of splatting
82
+ @object.public_send(scope, args)
83
+ else
84
+ @object.public_send(scope, *args)
85
+ end
86
+ end
87
+
88
+ def scope_arity(scope)
89
+ @klass.method(scope).arity
90
+ end
91
+
92
+ def bind(object, str)
93
+ return nil unless str
94
+ object.parent, object.attr_name = bind_pair_for(str)
95
+ end
96
+
97
+ def traverse(str, base = @base)
98
+ str ||= ''.freeze
99
+ segments = str.split(Constants::UNDERSCORE)
100
+ unless segments.empty?
101
+ remainder = []
102
+ found_assoc = nil
103
+ until found_assoc || segments.empty?
104
+ # Strip the _of_Model_type text from the association name, but hold
105
+ # onto it in klass, for use as the next base
106
+ assoc, klass = unpolymorphize_association(
107
+ segments.join(Constants::UNDERSCORE)
108
+ )
109
+ if found_assoc = get_association(assoc, base)
110
+ base = traverse(
111
+ remainder.join(Constants::UNDERSCORE), klass || found_assoc.klass
112
+ )
113
+ end
114
+
115
+ remainder.unshift segments.pop
116
+ end
117
+ unless found_assoc
118
+ raise(UntraversableAssociationError,
119
+ "No association matches #{str}")
120
+ end
121
+ end
122
+
123
+ klassify(base)
124
+ end
125
+
126
+ def association_path(str, base = @base)
127
+ base = klassify(base)
128
+ str ||= ''.freeze
129
+ path = []
130
+ segments = str.split(Constants::UNDERSCORE)
131
+ association_parts = []
132
+ unless segments.empty?
133
+ while !segments.empty? &&
134
+ !base.columns_hash[segments.join(Constants::UNDERSCORE)] &&
135
+ association_parts << segments.shift
136
+ assoc, klass = unpolymorphize_association(
137
+ association_parts.join(Constants::UNDERSCORE)
138
+ )
139
+ next unless found_assoc = get_association(assoc, base)
140
+ path += association_parts
141
+ association_parts = []
142
+ base = klassify(klass || found_assoc)
143
+ end
144
+ end
145
+
146
+ path.join(Constants::UNDERSCORE)
147
+ end
148
+
149
+ def unpolymorphize_association(str)
150
+ if (match = str.match(/_of_([^_]+?)_type$/))
151
+ [match.pre_match, Kernel.const_get(match.captures.first)]
152
+ else
153
+ [str, nil]
154
+ end
155
+ end
156
+
157
+ def ransackable_alias(str)
158
+ klass._ransack_aliases.fetch(str, klass._ransack_aliases.fetch(str.to_sym, str))
159
+ end
160
+
161
+ def ransackable_attribute?(str, klass)
162
+ klass.ransackable_attributes(auth_object).any? { |s| s.to_sym == str.to_sym } ||
163
+ klass.ransortable_attributes(auth_object).any? { |s| s.to_sym == str.to_sym }
164
+ end
165
+
166
+ def ransackable_association?(str, klass)
167
+ klass.ransackable_associations(auth_object).any? { |s| s.to_sym == str.to_sym }
168
+ end
169
+
170
+ def ransackable_scope?(str, klass)
171
+ klass.ransackable_scopes(auth_object).any? { |s| s.to_sym == str.to_sym }
172
+ end
173
+
174
+ def ransackable_scope_skip_sanitize_args?(str, klass)
175
+ klass.ransackable_scopes_skip_sanitize_args.any? { |s| s.to_sym == str.to_sym }
176
+ end
177
+
178
+ def searchable_attributes(str = ''.freeze)
179
+ traverse(str).ransackable_attributes(auth_object)
180
+ end
181
+
182
+ def sortable_attributes(str = ''.freeze)
183
+ traverse(str).ransortable_attributes(auth_object)
184
+ end
185
+
186
+ def searchable_associations(str = ''.freeze)
187
+ traverse(str).ransackable_associations(auth_object)
188
+ end
189
+ end
190
+ end