mobility 0.8.8 → 1.0.0.alpha
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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/CHANGELOG.md +56 -0
- data/Gemfile +52 -16
- data/Gemfile.lock +113 -52
- data/Guardfile +23 -1
- data/README.md +184 -92
- data/Rakefile +6 -4
- data/lib/mobility.rb +40 -166
- data/lib/mobility/active_record/translation.rb +1 -1
- data/lib/mobility/arel/nodes/pg_ops.rb +1 -1
- data/lib/mobility/backend.rb +19 -41
- data/lib/mobility/backends.rb +20 -0
- data/lib/mobility/backends/active_record.rb +4 -0
- data/lib/mobility/backends/active_record/column.rb +2 -0
- data/lib/mobility/backends/active_record/container.rb +4 -2
- data/lib/mobility/backends/active_record/hstore.rb +2 -0
- data/lib/mobility/backends/active_record/json.rb +2 -0
- data/lib/mobility/backends/active_record/jsonb.rb +2 -0
- data/lib/mobility/backends/active_record/key_value.rb +5 -3
- data/lib/mobility/backends/active_record/pg_hash.rb +1 -1
- data/lib/mobility/backends/active_record/serialized.rb +2 -0
- data/lib/mobility/backends/active_record/table.rb +5 -3
- data/lib/mobility/backends/column.rb +0 -6
- data/lib/mobility/backends/container.rb +2 -1
- data/lib/mobility/backends/hash.rb +39 -0
- data/lib/mobility/backends/hstore.rb +0 -1
- data/lib/mobility/backends/json.rb +0 -1
- data/lib/mobility/backends/jsonb.rb +0 -1
- data/lib/mobility/backends/key_value.rb +22 -14
- data/lib/mobility/backends/null.rb +2 -0
- data/lib/mobility/backends/sequel.rb +3 -0
- data/lib/mobility/backends/sequel/column.rb +2 -0
- data/lib/mobility/backends/sequel/container.rb +3 -1
- data/lib/mobility/backends/sequel/hstore.rb +2 -0
- data/lib/mobility/backends/sequel/json.rb +2 -0
- data/lib/mobility/backends/sequel/jsonb.rb +3 -1
- data/lib/mobility/backends/sequel/key_value.rb +8 -6
- data/lib/mobility/backends/sequel/serialized.rb +2 -0
- data/lib/mobility/backends/sequel/table.rb +5 -2
- data/lib/mobility/backends/serialized.rb +1 -3
- data/lib/mobility/backends/table.rb +14 -6
- data/lib/mobility/pluggable.rb +36 -0
- data/lib/mobility/plugin.rb +260 -0
- data/lib/mobility/plugins.rb +26 -25
- data/lib/mobility/plugins/active_model.rb +17 -0
- data/lib/mobility/plugins/active_model/cache.rb +26 -0
- data/lib/mobility/plugins/active_model/dirty.rb +310 -54
- data/lib/mobility/plugins/active_record.rb +34 -0
- data/lib/mobility/plugins/active_record/backend.rb +25 -0
- data/lib/mobility/plugins/active_record/cache.rb +28 -0
- data/lib/mobility/plugins/active_record/dirty.rb +72 -101
- data/lib/mobility/plugins/active_record/query.rb +48 -34
- data/lib/mobility/plugins/active_record/uniqueness_validation.rb +60 -0
- data/lib/mobility/plugins/attribute_methods.rb +28 -20
- data/lib/mobility/plugins/attributes.rb +70 -0
- data/lib/mobility/plugins/backend.rb +138 -0
- data/lib/mobility/plugins/backend_reader.rb +34 -0
- data/lib/mobility/plugins/cache.rb +59 -24
- data/lib/mobility/plugins/default.rb +22 -17
- data/lib/mobility/plugins/dirty.rb +12 -33
- data/lib/mobility/plugins/fallbacks.rb +51 -43
- data/lib/mobility/plugins/fallthrough_accessors.rb +26 -25
- data/lib/mobility/plugins/locale_accessors.rb +25 -35
- data/lib/mobility/plugins/presence.rb +28 -21
- data/lib/mobility/plugins/query.rb +8 -17
- data/lib/mobility/plugins/reader.rb +50 -0
- data/lib/mobility/plugins/sequel.rb +34 -0
- data/lib/mobility/plugins/sequel/backend.rb +25 -0
- data/lib/mobility/plugins/sequel/cache.rb +24 -0
- data/lib/mobility/plugins/sequel/dirty.rb +45 -32
- data/lib/mobility/plugins/sequel/query.rb +21 -6
- data/lib/mobility/plugins/writer.rb +44 -0
- data/lib/mobility/translations.rb +95 -0
- data/lib/mobility/version.rb +12 -1
- data/lib/rails/generators/mobility/templates/initializer.rb +95 -77
- metadata +51 -51
- metadata.gz.sig +0 -0
- data/lib/mobility/active_model.rb +0 -4
- data/lib/mobility/active_model/backend_resetter.rb +0 -26
- data/lib/mobility/active_record.rb +0 -23
- data/lib/mobility/active_record/backend_resetter.rb +0 -26
- data/lib/mobility/active_record/uniqueness_validator.rb +0 -60
- data/lib/mobility/attributes.rb +0 -324
- data/lib/mobility/backend/orm_delegator.rb +0 -44
- data/lib/mobility/backend_resetter.rb +0 -50
- data/lib/mobility/configuration.rb +0 -138
- data/lib/mobility/fallbacks.rb +0 -28
- data/lib/mobility/interface.rb +0 -0
- data/lib/mobility/loaded.rb +0 -4
- data/lib/mobility/plugins/active_record/attribute_methods.rb +0 -38
- data/lib/mobility/plugins/cache/translation_cacher.rb +0 -40
- data/lib/mobility/sequel.rb +0 -9
- data/lib/mobility/sequel/backend_resetter.rb +0 -23
- data/lib/mobility/translates.rb +0 -73
@@ -1,6 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require "mobility/backend_resetter"
|
3
|
-
require "mobility/plugins/fallthrough_accessors"
|
4
2
|
|
5
3
|
module Mobility
|
6
4
|
module Plugins
|
@@ -20,40 +18,21 @@ details.
|
|
20
18
|
|
21
19
|
=end
|
22
20
|
module Dirty
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
# @param [Boolean] option Value of option
|
27
|
-
# @raise [ArgumentError] if model class does not support dirty tracking
|
28
|
-
def apply(attributes, option)
|
29
|
-
if option
|
30
|
-
FallthroughAccessors.apply(attributes, true)
|
31
|
-
include_dirty_module(attributes.backend_class, attributes.model_class, *attributes.names)
|
32
|
-
end
|
33
|
-
end
|
21
|
+
extend Plugin
|
22
|
+
|
23
|
+
default true
|
34
24
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
Plugins::ActiveRecord::Dirty
|
43
|
-
else
|
44
|
-
require "mobility/plugins/active_model/dirty"
|
45
|
-
Plugins::ActiveModel::Dirty
|
46
|
-
end
|
47
|
-
elsif Loaded::Sequel && model_class < ::Sequel::Model
|
48
|
-
require "mobility/plugins/sequel/dirty"
|
49
|
-
Plugins::Sequel::Dirty
|
50
|
-
else
|
51
|
-
raise ArgumentError, "#{model_class} does not support Dirty module."
|
52
|
-
end
|
53
|
-
backend_class.include dirty_module
|
54
|
-
model_class.include dirty_module.const_get(:MethodsBuilder).new(*attribute_names)
|
25
|
+
requires :backend, include: :before
|
26
|
+
requires :fallthrough_accessors
|
27
|
+
|
28
|
+
initialize_hook do
|
29
|
+
if options[:dirty] && !options[:fallthrough_accessors]
|
30
|
+
warn 'The Dirty plugin depends on Fallthrough Accessors being enabled, '\
|
31
|
+
'but fallthrough_accessors option is falsey'
|
55
32
|
end
|
56
33
|
end
|
57
34
|
end
|
35
|
+
|
36
|
+
register_plugin(:dirty, Dirty)
|
58
37
|
end
|
59
38
|
end
|
@@ -8,15 +8,14 @@ module Mobility
|
|
8
8
|
Falls back to one or more alternative locales in case no value is defined for a
|
9
9
|
given locale.
|
10
10
|
|
11
|
-
For +fallbacks: true+, Mobility will use
|
12
|
-
|
13
|
-
|
14
|
-
configured (see {Mobility::Configuration}).
|
11
|
+
For +fallbacks: true+, Mobility will use an instance of
|
12
|
+
+I18n::Locale::Fallbacks+, but this can be configured by overriding
|
13
|
+
+generate_fallbacks+ in the translations class.
|
15
14
|
|
16
15
|
If a hash is passed to the +fallbacks+ option, a new fallbacks instance will be
|
17
16
|
created for the model with the hash defining additional fallbacks. To set a
|
18
|
-
default value for this hash,
|
19
|
-
|
17
|
+
default value for this hash, pass this value to the plugin in your Mobility
|
18
|
+
configuration.
|
20
19
|
|
21
20
|
In addition, fallbacks are disabled in certain situations. To explicitly disable
|
22
21
|
fallbacks when reading and writing, you can pass the <tt>fallback: false</tt>
|
@@ -108,58 +107,67 @@ the current locale was +nil+.
|
|
108
107
|
#=> nil
|
109
108
|
post.title_fr
|
110
109
|
#=> nil
|
110
|
+
=end
|
111
|
+
module Fallbacks
|
112
|
+
extend Plugin
|
111
113
|
|
112
|
-
|
113
|
-
|
114
|
-
# ...
|
115
|
-
config.default_options[:fallbacks] = { :'fr' => 'en' }
|
116
|
-
# ...
|
117
|
-
end
|
118
|
-
|
119
|
-
class Post
|
120
|
-
# Post will fallback from French to English by default
|
121
|
-
translates :title, fallbacks: true
|
122
|
-
end
|
114
|
+
default true
|
115
|
+
requires :backend, include: :before
|
123
116
|
|
124
|
-
=end
|
125
|
-
class Fallbacks < Module
|
126
117
|
# Applies fallbacks plugin to attributes. Completely disables fallbacks
|
127
118
|
# on model if option is +false+.
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
attributes.backend_class.include(new(option)) unless option == false
|
119
|
+
included_hook do |_, backend_class|
|
120
|
+
fallbacks = options[:fallbacks]
|
121
|
+
backend_class.include(BackendReader.new(fallbacks, method(:generate_fallbacks))) unless fallbacks == false
|
132
122
|
end
|
133
123
|
|
134
|
-
|
135
|
-
|
124
|
+
private
|
125
|
+
|
126
|
+
def generate_fallbacks(fallbacks)
|
127
|
+
fallbacks_class = I18n.respond_to?(:fallbacks) ? I18nFallbacks : I18n::Locale::Fallbacks
|
128
|
+
fallbacks_class.new(fallbacks)
|
136
129
|
end
|
137
130
|
|
138
|
-
|
131
|
+
class I18nFallbacks < ::I18n::Locale::Fallbacks
|
132
|
+
def [](locale)
|
133
|
+
super | I18n.fallbacks[locale]
|
134
|
+
end
|
135
|
+
end
|
139
136
|
|
140
|
-
|
141
|
-
|
142
|
-
|
137
|
+
class BackendReader < Module
|
138
|
+
def initialize(fallbacks_option, fallbacks_generator)
|
139
|
+
@fallbacks_generator = fallbacks_generator
|
140
|
+
define_read(convert_option_to_fallbacks(fallbacks_option))
|
141
|
+
end
|
143
142
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
143
|
+
private
|
144
|
+
|
145
|
+
def define_read(fallbacks)
|
146
|
+
define_method :read do |locale, fallback: true, **options|
|
147
|
+
return super(locale, options) if !fallback || options[:locale]
|
149
148
|
|
150
|
-
|
149
|
+
locales = fallback == true ? fallbacks[locale] : [locale, *fallback]
|
150
|
+
locales.each do |fallback_locale|
|
151
|
+
value = super(fallback_locale, options)
|
152
|
+
return value if Util.present?(value)
|
153
|
+
end
|
154
|
+
|
155
|
+
super(locale, options)
|
156
|
+
end
|
151
157
|
end
|
152
|
-
end
|
153
158
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
159
|
+
def convert_option_to_fallbacks(option)
|
160
|
+
if option.is_a?(::Hash)
|
161
|
+
@fallbacks_generator[option]
|
162
|
+
elsif option == true
|
163
|
+
@fallbacks_generator[{}]
|
164
|
+
else
|
165
|
+
::Hash.new { [] }
|
166
|
+
end
|
161
167
|
end
|
162
168
|
end
|
163
169
|
end
|
170
|
+
|
171
|
+
register_plugin(:fallbacks, Fallbacks)
|
164
172
|
end
|
165
173
|
end
|
@@ -18,42 +18,41 @@ This is a less efficient (but more open-ended) implementation of locale
|
|
18
18
|
accessors, for use in cases where the locales to be used are not known when the
|
19
19
|
model class is generated.
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
"title in #{Mobility.locale}"
|
25
|
-
end
|
26
|
-
include Mobility::FallthroughAccessors.new("title")
|
27
|
-
end
|
21
|
+
=end
|
22
|
+
module FallthroughAccessors
|
23
|
+
extend Plugin
|
28
24
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
post.title_fr
|
34
|
-
#=> "title in fr"
|
25
|
+
default true
|
26
|
+
|
27
|
+
requires :reader
|
28
|
+
requires :writer
|
35
29
|
|
36
|
-
=end
|
37
|
-
class FallthroughAccessors < Module
|
38
30
|
# Apply fallthrough accessors plugin to attributes.
|
39
|
-
# @param [
|
31
|
+
# @param [Translations] translations
|
40
32
|
# @param [Boolean] option
|
41
|
-
|
42
|
-
|
33
|
+
initialize_hook do
|
34
|
+
if options[:fallthrough_accessors] && options[:reader] && options[:writer]
|
35
|
+
define_fallthrough_accessors(names)
|
36
|
+
end
|
43
37
|
end
|
44
38
|
|
45
|
-
|
46
|
-
def initialize(*attributes)
|
47
|
-
method_name_regex = /\A(#{attributes.join('|')})_([a-z]{2}(_[a-z]{2})?)(=?|\??)\z/.freeze
|
39
|
+
private
|
48
40
|
|
49
|
-
|
41
|
+
def define_fallthrough_accessors(*names)
|
42
|
+
method_name_regex = /\A(#{names.join('|')})_([a-z]{2}(_[a-z]{2})?)(=?|\??)\z/.freeze
|
43
|
+
|
44
|
+
define_method :method_missing do |method_name, *args, &block|
|
50
45
|
if method_name =~ method_name_regex
|
51
|
-
|
46
|
+
attribute_method = "#{$1}#{$4}"
|
52
47
|
locale, suffix = $2.split('_')
|
53
48
|
locale = "#{locale}-#{suffix.upcase}" if suffix
|
54
|
-
|
49
|
+
if $4 == '=' # writer
|
50
|
+
public_send(attribute_method, args[0], **(args[1] || {}), locale: locale)
|
51
|
+
else # reader
|
52
|
+
public_send(attribute_method, **(args[0] || {}), locale: locale)
|
53
|
+
end
|
55
54
|
else
|
56
|
-
super(method_name, *
|
55
|
+
super(method_name, *args, &block)
|
57
56
|
end
|
58
57
|
end
|
59
58
|
|
@@ -62,5 +61,7 @@ model class is generated.
|
|
62
61
|
end
|
63
62
|
end
|
64
63
|
end
|
64
|
+
|
65
|
+
register_plugin :fallthrough_accessors, FallthroughAccessors
|
65
66
|
end
|
66
67
|
end
|
@@ -13,47 +13,33 @@ If no locales are passed as an option to the initializer,
|
|
13
13
|
+Mobility.available_locales+ (i.e. +I18n.available_locales+, or Rails-set
|
14
14
|
available locales for a Rails application) will be used by default.
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
"title in #{Mobility.locale}"
|
20
|
-
end
|
21
|
-
include Mobility::Plugins::LocaleAccessors.new("title", locales: [:en, :fr])
|
22
|
-
end
|
16
|
+
=end
|
17
|
+
module LocaleAccessors
|
18
|
+
extend Plugin
|
23
19
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
post.title_fr
|
29
|
-
#=> "title in fr"
|
20
|
+
default true
|
21
|
+
|
22
|
+
requires :reader
|
23
|
+
requires :writer
|
30
24
|
|
31
|
-
=end
|
32
|
-
class LocaleAccessors < Module
|
33
25
|
# Apply locale accessors plugin to attributes.
|
34
|
-
# @param [
|
26
|
+
# @param [Translations] translations
|
35
27
|
# @param [Boolean] option
|
36
|
-
|
37
|
-
if
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
# @param [Array<Symbol>] Locales
|
45
|
-
def initialize(*attribute_names, locales:)
|
46
|
-
attribute_names.each do |name|
|
47
|
-
locales.each do |locale|
|
48
|
-
define_reader(name, locale)
|
49
|
-
define_writer(name, locale)
|
28
|
+
initialize_hook do |*names|
|
29
|
+
if locales = options[:locale_accessors]
|
30
|
+
locales = Mobility.available_locales if locales == true
|
31
|
+
names.each do |name|
|
32
|
+
locales.each do |locale|
|
33
|
+
define_locale_reader(name, locale) if options[:reader]
|
34
|
+
define_locale_writer(name, locale) if options[:writer]
|
35
|
+
end
|
50
36
|
end
|
51
37
|
end
|
52
38
|
end
|
53
39
|
|
54
40
|
private
|
55
41
|
|
56
|
-
def
|
42
|
+
def define_locale_reader(name, locale)
|
57
43
|
warning_message = "locale passed as option to locale accessor will be ignored"
|
58
44
|
normalized_locale = Mobility.normalize_locale(locale)
|
59
45
|
|
@@ -61,18 +47,20 @@ available locales for a Rails application) will be used by default.
|
|
61
47
|
def #{name}_#{normalized_locale}(options = {})
|
62
48
|
return super() if options.delete(:super)
|
63
49
|
warn "#{warning_message}" if options[:locale]
|
64
|
-
#{name}(**options, locale:
|
50
|
+
#{name}(**options, locale: #{locale.inspect})
|
65
51
|
end
|
52
|
+
EOM
|
66
53
|
|
54
|
+
module_eval <<-EOM, __FILE__, __LINE__ + 1
|
67
55
|
def #{name}_#{normalized_locale}?(options = {})
|
68
56
|
return super() if options.delete(:super)
|
69
57
|
warn "#{warning_message}" if options[:locale]
|
70
|
-
#{name}?(**options, locale:
|
58
|
+
#{name}?(**options, locale: #{locale.inspect})
|
71
59
|
end
|
72
60
|
EOM
|
73
61
|
end
|
74
62
|
|
75
|
-
def
|
63
|
+
def define_locale_writer(name, locale)
|
76
64
|
warning_message = "locale passed as option to locale accessor will be ignored"
|
77
65
|
normalized_locale = Mobility.normalize_locale(locale)
|
78
66
|
|
@@ -80,10 +68,12 @@ available locales for a Rails application) will be used by default.
|
|
80
68
|
def #{name}_#{normalized_locale}=(value, options = {})
|
81
69
|
return super(value) if options.delete(:super)
|
82
70
|
warn "#{warning_message}" if options[:locale]
|
83
|
-
public_send(:#{name}=, value, **options, locale:
|
71
|
+
public_send(:#{name}=, value, **options, locale: #{locale.inspect})
|
84
72
|
end
|
85
73
|
EOM
|
86
74
|
end
|
87
75
|
end
|
76
|
+
|
77
|
+
register_plugin(:locale_accessors, LocaleAccessors)
|
88
78
|
end
|
89
79
|
end
|
@@ -6,43 +6,50 @@ module Mobility
|
|
6
6
|
=begin
|
7
7
|
|
8
8
|
Applies presence filter to values fetched from backend and to values set on
|
9
|
-
backend.
|
9
|
+
backend.
|
10
10
|
|
11
11
|
@note For performance reasons, the presence plugin filters only for empty
|
12
12
|
strings, not other values continued "blank" like empty arrays.
|
13
13
|
|
14
14
|
=end
|
15
15
|
module Presence
|
16
|
+
extend Plugin
|
17
|
+
|
18
|
+
default true
|
19
|
+
requires :backend, include: :before
|
20
|
+
|
16
21
|
# Applies presence plugin to attributes.
|
17
|
-
|
18
|
-
|
19
|
-
def self.apply(attributes, option)
|
20
|
-
attributes.backend_class.include(self) if option
|
22
|
+
included_hook do |_, backend_class|
|
23
|
+
backend_class.include(BackendMethods) if options[:presence]
|
21
24
|
end
|
22
25
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
options
|
29
|
-
|
26
|
+
module BackendMethods
|
27
|
+
# @!group Backend Accessors
|
28
|
+
# @!macro backend_reader
|
29
|
+
# @option options [Boolean] presence
|
30
|
+
# *false* to disable presence filter.
|
31
|
+
def read(locale, **options)
|
32
|
+
options.delete(:presence) == false ? super : Presence[super]
|
33
|
+
end
|
30
34
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
# @!macro backend_writer
|
36
|
+
# @option options [Boolean] presence
|
37
|
+
# *false* to disable presence filter.
|
38
|
+
def write(locale, value, **options)
|
39
|
+
if options.delete(:presence) == false
|
40
|
+
super
|
41
|
+
else
|
42
|
+
super(locale, Presence[value], options)
|
43
|
+
end
|
39
44
|
end
|
45
|
+
# @!endgroup
|
40
46
|
end
|
41
|
-
# @!endgroup
|
42
47
|
|
43
48
|
def self.[](value)
|
44
49
|
(value == "") ? nil : value
|
45
50
|
end
|
46
51
|
end
|
52
|
+
|
53
|
+
register_plugin(:presence, Presence)
|
47
54
|
end
|
48
55
|
end
|
@@ -3,29 +3,20 @@ module Mobility
|
|
3
3
|
module Plugins
|
4
4
|
=begin
|
5
5
|
|
6
|
-
@see {Mobility::Plugins::ActiveRecord::Query}
|
6
|
+
@see {Mobility::Plugins::ActiveRecord::Query} or {Mobility::Plugins::Sequel::Query}.
|
7
7
|
|
8
8
|
=end
|
9
9
|
module Query
|
10
|
-
|
11
|
-
def apply(attributes, option)
|
12
|
-
if option
|
13
|
-
include_query_module(attributes)
|
14
|
-
end
|
15
|
-
end
|
10
|
+
extend Plugin
|
16
11
|
|
17
|
-
|
12
|
+
default :i18n
|
13
|
+
requires :backend, include: :before
|
18
14
|
|
19
|
-
|
20
|
-
|
21
|
-
require "mobility/plugins/active_record/query"
|
22
|
-
ActiveRecord::Query.apply(attributes)
|
23
|
-
elsif Loaded::Sequel && attributes.model_class < ::Sequel::Model
|
24
|
-
require "mobility/plugins/sequel/query"
|
25
|
-
Sequel::Query.apply(attributes)
|
26
|
-
end
|
27
|
-
end
|
15
|
+
def query_method
|
16
|
+
(options[:query] == true) ? self.class.defaults[:query] : options[:query]
|
28
17
|
end
|
29
18
|
end
|
19
|
+
|
20
|
+
register_plugin(:query, Query)
|
30
21
|
end
|
31
22
|
end
|