mobility 0.1.20 → 0.2.0

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 (110) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +2 -0
  4. data/CHANGELOG.md +17 -0
  5. data/CONTRIBUTING.md +55 -0
  6. data/Gemfile +2 -0
  7. data/Gemfile.lock +2 -56
  8. data/README.md +64 -15
  9. data/Rakefile +17 -17
  10. data/lib/mobility.rb +43 -40
  11. data/lib/mobility/active_model.rb +0 -1
  12. data/lib/mobility/active_model/backend_resetter.rb +1 -1
  13. data/lib/mobility/active_record.rb +8 -15
  14. data/lib/mobility/active_record/backend_resetter.rb +2 -0
  15. data/lib/mobility/active_record/model_translation.rb +1 -1
  16. data/lib/mobility/active_record/string_translation.rb +2 -0
  17. data/lib/mobility/active_record/text_translation.rb +2 -0
  18. data/lib/mobility/attributes.rb +74 -71
  19. data/lib/mobility/backend.rb +64 -25
  20. data/lib/mobility/backend/orm_delegator.rb +17 -7
  21. data/lib/mobility/backend/stringify_locale.rb +18 -0
  22. data/lib/mobility/backend_resetter.rb +8 -5
  23. data/lib/mobility/backends.rb +4 -0
  24. data/lib/mobility/backends/active_record.rb +20 -0
  25. data/lib/mobility/{backend → backends}/active_record/column.rb +25 -13
  26. data/lib/mobility/{backend → backends}/active_record/column/query_methods.rb +5 -3
  27. data/lib/mobility/backends/active_record/hstore.rb +29 -0
  28. data/lib/mobility/{backend → backends}/active_record/hstore/query_methods.rb +2 -2
  29. data/lib/mobility/{backend → backends}/active_record/jsonb.rb +6 -6
  30. data/lib/mobility/{backend → backends}/active_record/jsonb/query_methods.rb +4 -2
  31. data/lib/mobility/{backend → backends}/active_record/key_value.rb +10 -44
  32. data/lib/mobility/{backend → backends}/active_record/key_value/query_methods.rb +4 -2
  33. data/lib/mobility/{backend/active_record/hash_valued.rb → backends/active_record/pg_hash.rb} +13 -21
  34. data/lib/mobility/{backend → backends}/active_record/query_methods.rb +2 -2
  35. data/lib/mobility/{backend → backends}/active_record/serialized.rb +12 -28
  36. data/lib/mobility/{backend → backends}/active_record/serialized/query_methods.rb +5 -8
  37. data/lib/mobility/{backend → backends}/active_record/table.rb +11 -60
  38. data/lib/mobility/{backend → backends}/active_record/table/query_methods.rb +5 -3
  39. data/lib/mobility/{backend → backends}/column.rb +8 -4
  40. data/lib/mobility/backends/hash_valued.rb +29 -0
  41. data/lib/mobility/{backend → backends}/hstore.rb +4 -4
  42. data/lib/mobility/{backend → backends}/jsonb.rb +4 -4
  43. data/lib/mobility/backends/key_value.rb +111 -0
  44. data/lib/mobility/{backend → backends}/null.rb +4 -4
  45. data/lib/mobility/backends/sequel.rb +20 -0
  46. data/lib/mobility/backends/sequel/column.rb +52 -0
  47. data/lib/mobility/{backend → backends}/sequel/column/query_methods.rb +5 -3
  48. data/lib/mobility/backends/sequel/hstore.rb +29 -0
  49. data/lib/mobility/{backend → backends}/sequel/hstore/query_methods.rb +4 -3
  50. data/lib/mobility/{backend → backends}/sequel/jsonb.rb +6 -6
  51. data/lib/mobility/{backend → backends}/sequel/jsonb/query_methods.rb +4 -3
  52. data/lib/mobility/{backend → backends}/sequel/key_value.rb +28 -39
  53. data/lib/mobility/{backend → backends}/sequel/key_value/query_methods.rb +4 -5
  54. data/lib/mobility/backends/sequel/pg_hash.rb +46 -0
  55. data/lib/mobility/{backend → backends}/sequel/postgres_query_methods.rb +1 -2
  56. data/lib/mobility/{backend → backends}/sequel/query_methods.rb +6 -4
  57. data/lib/mobility/{backend → backends}/sequel/serialized.rb +17 -38
  58. data/lib/mobility/backends/sequel/serialized/query_methods.rb +17 -0
  59. data/lib/mobility/{backend → backends}/sequel/table.rb +29 -60
  60. data/lib/mobility/{backend → backends}/sequel/table/query_methods.rb +5 -3
  61. data/lib/mobility/{backend → backends}/serialized.rb +27 -5
  62. data/lib/mobility/{backend → backends}/table.rb +69 -29
  63. data/lib/mobility/configuration.rb +40 -0
  64. data/lib/mobility/{orm.rb → loaded.rb} +0 -0
  65. data/lib/mobility/plugins.rb +35 -0
  66. data/lib/mobility/plugins/active_model.rb +6 -0
  67. data/lib/mobility/plugins/active_model/dirty.rb +81 -0
  68. data/lib/mobility/plugins/active_record.rb +6 -0
  69. data/lib/mobility/plugins/active_record/dirty.rb +59 -0
  70. data/lib/mobility/plugins/cache.rb +54 -0
  71. data/lib/mobility/plugins/cache/translation_cacher.rb +40 -0
  72. data/lib/mobility/plugins/default.rb +73 -0
  73. data/lib/mobility/plugins/dirty.rb +61 -0
  74. data/lib/mobility/{backend → plugins}/fallbacks.rb +36 -31
  75. data/lib/mobility/plugins/fallthrough_accessors.rb +66 -0
  76. data/lib/mobility/plugins/locale_accessors.rb +84 -0
  77. data/lib/mobility/{backend → plugins}/presence.rb +15 -6
  78. data/lib/mobility/plugins/sequel.rb +6 -0
  79. data/lib/mobility/plugins/sequel/dirty.rb +59 -0
  80. data/lib/mobility/sequel.rb +5 -14
  81. data/lib/mobility/sequel/backend_resetter.rb +4 -6
  82. data/lib/mobility/sequel/column_changes.rb +4 -4
  83. data/lib/mobility/sequel/model_translation.rb +1 -1
  84. data/lib/mobility/sequel/string_translation.rb +2 -0
  85. data/lib/mobility/sequel/text_translation.rb +2 -0
  86. data/lib/mobility/translates.rb +1 -5
  87. data/lib/mobility/util.rb +126 -0
  88. data/lib/mobility/version.rb +1 -1
  89. data/lib/mobility/wrapper.rb +1 -1
  90. data/lib/rails/generators/mobility/translations_generator.rb +7 -3
  91. metadata +85 -55
  92. metadata.gz.sig +0 -0
  93. data/lib/mobility/backend/active_model.rb +0 -7
  94. data/lib/mobility/backend/active_model/dirty.rb +0 -95
  95. data/lib/mobility/backend/active_record.rb +0 -29
  96. data/lib/mobility/backend/active_record/dirty.rb +0 -54
  97. data/lib/mobility/backend/active_record/hstore.rb +0 -29
  98. data/lib/mobility/backend/cache.rb +0 -117
  99. data/lib/mobility/backend/dirty.rb +0 -38
  100. data/lib/mobility/backend/key_value.rb +0 -85
  101. data/lib/mobility/backend/sequel.rb +0 -29
  102. data/lib/mobility/backend/sequel/column.rb +0 -39
  103. data/lib/mobility/backend/sequel/dirty.rb +0 -57
  104. data/lib/mobility/backend/sequel/hash_valued.rb +0 -51
  105. data/lib/mobility/backend/sequel/hstore.rb +0 -29
  106. data/lib/mobility/backend/sequel/serialized/query_methods.rb +0 -20
  107. data/lib/mobility/core_ext/object.rb +0 -30
  108. data/lib/mobility/core_ext/string.rb +0 -16
  109. data/lib/mobility/fallthrough_accessors.rb +0 -57
  110. data/lib/mobility/locale_accessors.rb +0 -55
data/lib/mobility.rb CHANGED
@@ -2,14 +2,6 @@ require 'i18n'
2
2
  require 'request_store'
3
3
  require 'mobility/version'
4
4
 
5
- %w[object string].each do |type|
6
- begin
7
- require "active_support/core_ext/#{type}"
8
- rescue LoadError
9
- require "mobility/core_ext/#{type}"
10
- end
11
- end
12
-
13
5
  =begin
14
6
 
15
7
  Mobility is a gem for storing and retrieving localized data through attributes
@@ -21,7 +13,7 @@ and define any attribute accessors using {Translates#mobility_accessor} (aliased
21
13
  value of {Mobility.accessor_method}, which defaults to +translates+).
22
14
 
23
15
  class MyClass
24
- include Mobility
16
+ extend Mobility
25
17
  translates :title, backend: :key_value
26
18
  end
27
19
 
@@ -32,16 +24,15 @@ in backends to define gem-dependent behavior.
32
24
 
33
25
  =end
34
26
  module Mobility
35
- autoload :Attributes, "mobility/attributes"
36
- autoload :Backend, "mobility/backend"
37
- autoload :BackendResetter, "mobility/backend_resetter"
38
- autoload :Configuration, "mobility/configuration"
39
- autoload :FallthroughAccessors, "mobility/fallthrough_accessors"
40
- autoload :LocaleAccessors, "mobility/locale_accessors"
41
- autoload :Translates, "mobility/translates"
42
- autoload :Wrapper, "mobility/wrapper"
43
-
44
- require "mobility/orm"
27
+ require "mobility/attributes"
28
+ require "mobility/backend"
29
+ require "mobility/backends"
30
+ require "mobility/backend_resetter"
31
+ require "mobility/configuration"
32
+ require "mobility/loaded"
33
+ require "mobility/plugins"
34
+ require "mobility/translates"
35
+ require "mobility/wrapper"
45
36
 
46
37
  # General error for version compatibility conflicts
47
38
  class VersionNotSupportedError < ArgumentError; end
@@ -49,10 +40,11 @@ module Mobility
49
40
  begin
50
41
  require "active_record"
51
42
  raise VersionNotSupportedError, "Mobility is only compatible with ActiveRecord 4.2 and greater" if ::ActiveRecord::VERSION::STRING < "4.2"
52
- autoload :ActiveModel, "mobility/active_model"
53
- autoload :ActiveRecord, "mobility/active_record"
43
+ require "mobility/active_model"
44
+ require "mobility/active_record"
54
45
  Loaded::ActiveRecord = true
55
- rescue LoadError
46
+ rescue LoadError => e
47
+ raise unless e.message =~ /active_record/
56
48
  Loaded::ActiveRecord = false
57
49
  end
58
50
 
@@ -60,7 +52,8 @@ module Mobility
60
52
  require "rails"
61
53
  Loaded::Rails = true
62
54
  require "rails/generators/mobility/generators"
63
- rescue LoadError
55
+ rescue LoadError => e
56
+ raise unless e.message =~ /rails/
64
57
  Loaded::Rails = false
65
58
  end
66
59
 
@@ -68,32 +61,23 @@ module Mobility
68
61
  require "sequel"
69
62
  raise VersionNotSupportedError, "Mobility is only compatible with Sequel 4.0 and greater" if ::Sequel::MAJOR < 4
70
63
  require "sequel/plugins/mobility"
64
+ #TODO avoid automatically including the inflector extension
71
65
  require "sequel/extensions/inflector"
72
66
  require "sequel/plugins/dirty"
73
- autoload :Sequel, "mobility/sequel"
67
+ require "mobility/sequel"
74
68
  Loaded::Sequel = true
75
- rescue LoadError
69
+ rescue LoadError => e
70
+ raise unless e.message =~ /sequel/
76
71
  Loaded::Sequel = false
77
72
  end
78
73
 
79
74
  class << self
80
75
  def extended(model_class)
81
76
  return if model_class.respond_to? :mobility_accessor
82
- mod = Module.new do
83
- # Fetch backend for an attribute
84
- # @param [String] attribute Attribute
85
- def mobility_backend_for(attribute)
86
- send(Backend.method_name(attribute))
87
- end
88
-
89
- def initialize_dup(other)
90
- @mobility_backends = nil
91
- super
92
- end
93
- end
94
- model_class.include(mod)
95
77
 
78
+ model_class.include(InstanceMethods)
96
79
  model_class.extend(ClassMethods)
80
+
97
81
  if translates = Mobility.config.accessor_method
98
82
  model_class.singleton_class.send(:alias_method, translates, :mobility_accessor)
99
83
  end
@@ -109,7 +93,7 @@ module Mobility
109
93
  end
110
94
 
111
95
  # Extends model with this class so that +include Mobility+ is equivalent to
112
- # +extend Mobility+
96
+ # +extend Mobility+ (but +extend+ is preferred).
113
97
  # @param model_class
114
98
  def included(model_class)
115
99
  model_class.extend self
@@ -167,9 +151,15 @@ module Mobility
167
151
  # (see Mobility::Configuration#default_backend)
168
152
  # @!method default_backend
169
153
 
154
+ # (see Mobility::Configuration#default_options)
155
+ # @!method default_options
156
+ #
157
+ # (see Mobility::Configuration#plugins)
158
+ # @!method plugins
159
+ #
170
160
  # (see Mobility::Configuration#default_accessor_locales)
171
161
  # @!method default_accessor_locales
172
- %w[accessor_method query_method default_backend default_accessor_locales].each do |method_name|
162
+ %w[accessor_method query_method default_backend default_options plugins default_accessor_locales].each do |method_name|
173
163
  define_method method_name do
174
164
  config.public_send(method_name)
175
165
  end
@@ -234,6 +224,19 @@ module Mobility
234
224
  end
235
225
  end
236
226
 
227
+ module InstanceMethods
228
+ # Fetch backend for an attribute
229
+ # @param [String] attribute Attribute
230
+ def mobility_backend_for(attribute)
231
+ send(Backend.method_name(attribute))
232
+ end
233
+
234
+ def initialize_dup(other)
235
+ @mobility_backends = nil
236
+ super
237
+ end
238
+ end
239
+
237
240
  module ClassMethods
238
241
  include Translates
239
242
 
@@ -1,5 +1,4 @@
1
1
  module Mobility
2
2
  module ActiveModel
3
- autoload :BackendResetter, "mobility/active_model/backend_resetter"
4
3
  end
5
4
  end
@@ -9,7 +9,7 @@ Backend resetter for ActiveModel models. Adds hook to reset backend when
9
9
  class BackendResetter < Mobility::BackendResetter
10
10
 
11
11
  # (see Mobility::BackendResetter#initialize)
12
- def initialize(attributes)
12
+ def initialize(attribute_names)
13
13
  super
14
14
 
15
15
  model_reset_method = @model_reset_method
@@ -5,25 +5,18 @@ Module loading ActiveRecord-specific classes for Mobility models.
5
5
 
6
6
  =end
7
7
  module ActiveRecord
8
- autoload :AttributeMethods, "mobility/active_record/attribute_methods"
9
- autoload :BackendResetter, "mobility/active_record/backend_resetter"
10
- autoload :ModelTranslation, "mobility/active_record/model_translation"
11
- autoload :StringTranslation, "mobility/active_record/string_translation"
12
- autoload :TextTranslation, "mobility/active_record/text_translation"
13
- autoload :Translation, "mobility/active_record/translation"
14
- autoload :UniquenessValidator, "mobility/active_record/uniqueness_validator"
8
+ require "mobility/active_record/attribute_methods"
9
+ require "mobility/active_record/uniqueness_validator"
15
10
 
16
11
  def self.included(model_class)
17
- model_class.extend(ClassMethods)
12
+ query_method = Module.new do
13
+ define_method Mobility.query_method do
14
+ all
15
+ end
16
+ end
17
+ model_class.extend query_method
18
18
  model_class.const_set(:UniquenessValidator,
19
19
  Class.new(::Mobility::ActiveRecord::UniquenessValidator))
20
20
  end
21
-
22
- module ClassMethods
23
- # @return [ActiveRecord::Relation] relation extended with Mobility query methods.
24
- define_method ::Mobility.query_method do
25
- all
26
- end
27
- end
28
21
  end
29
22
  end
@@ -1,3 +1,5 @@
1
+ require "mobility/active_model/backend_resetter"
2
+
1
3
  module Mobility
2
4
  module ActiveRecord
3
5
  =begin
@@ -3,7 +3,7 @@ module Mobility
3
3
  =begin
4
4
 
5
5
  Subclassed dynamically to generate translation class in
6
- {Backend::ActiveRecord::Table} backend.
6
+ {Backends::ActiveRecord::Table} backend.
7
7
 
8
8
  =end
9
9
  class ModelTranslation < ::ActiveRecord::Base
@@ -1,3 +1,5 @@
1
+ require "mobility/active_record/translation"
2
+
1
3
  module Mobility
2
4
  module ActiveRecord
3
5
  class StringTranslation < Translation
@@ -1,3 +1,5 @@
1
+ require "mobility/active_record/translation"
2
+
1
3
  module Mobility
2
4
  module ActiveRecord
3
5
  class TextTranslation < Translation
@@ -1,3 +1,5 @@
1
+ require "mobility/util"
2
+
1
3
  module Mobility
2
4
  =begin
3
5
 
@@ -15,15 +17,16 @@ understanding and designing backends.
15
17
  Since {Attributes} is a subclass of +Module+, including an instance of it is
16
18
  like including a module. Creating an instance like this:
17
19
 
18
- Attributes.new(:accessor, ["title"], backend: :my_backend, locale_accessors: [:en, :ja], cache: true, fallbacks: true)
20
+ Attributes.new("title", backend: :my_backend, locale_accessors: [:en, :ja], cache: true, fallbacks: true)
19
21
 
20
- will generate an anonymous module looking something like this:
22
+ will generate an anonymous module that behaves like this:
21
23
 
22
24
  Module.new do
23
25
  def title_backend
24
- # Create a subclass of Mobility::Backend::MyBackend and include in it:
25
- # - Mobility::Cache (from the cache: true option)
26
- # - Mobility::Fallbacks (from the fallbacks: true option)
26
+ # Create a subclass of Mobility::Backends::MyBackend and include in it:
27
+ # - Mobility::Plugins::Cache (from the +cache: true+ option)
28
+ # - Mobility::Plugins::Fallbacks (from the +fallbacks: true+ option)
29
+ # - Mobility::Plugins::Presence (by default, disabled by +presence: false+)
27
30
  # Then instantiate the backend, memoize it, and return it.
28
31
  end
29
32
 
@@ -67,9 +70,9 @@ will generate an anonymous module looking something like this:
67
70
  # End Locale Accessors
68
71
  end
69
72
 
70
- Including this module into a model class will then add the backend method, the
73
+ Including this module into a model class will thus add the backend method, the
71
74
  reader, writer and presence methods, and the locale accessor so the model
72
- class.
75
+ class. (These methods are in fact added to the model in an +included+ hook.)
73
76
 
74
77
  ==Setting up the Model Class
75
78
 
@@ -81,8 +84,8 @@ Assuming the backend has defined a setup block by calling +setup+, this block
81
84
  will be called when {Attributes} is {#included} in the model class, passed
82
85
  attributes and options defined when the backend was defined on the model class.
83
86
  This allows a backend to do things like (for example) define associations on a
84
- model class required by the backend, as happens in the {Backend::KeyValue} and
85
- {Backend::Table} backends.
87
+ model class required by the backend, as happens in the {Backends::KeyValue} and
88
+ {Backends::Table} backends.
86
89
 
87
90
  The +setup+ block is also used to extend the query scope/dataset (+i18n+ by
88
91
  default) with backend-specific query method support.
@@ -95,9 +98,14 @@ with other backends.
95
98
 
96
99
  =end
97
100
  class Attributes < Module
98
- # Attributes for which accessors will be defined
99
- # @return [Array<String>] Array of attributes
100
- attr_reader :attributes
101
+
102
+ # Method (accessor, reader or writer)
103
+ # @return [Symbol] method
104
+ attr_reader :method
105
+
106
+ # Attribute names for which accessors will be defined
107
+ # @return [Array<String>] Array of names
108
+ attr_reader :names
101
109
 
102
110
  # Backend options
103
111
  # @return [Hash] Backend options
@@ -111,106 +119,101 @@ with other backends.
111
119
  # @return [Symbol,Class] Name of backend, or backend class
112
120
  attr_reader :backend_name
113
121
 
122
+ # Model class
123
+ # @return [Class] Class of model
124
+ attr_reader :model_class
125
+
114
126
  # @param [Symbol] method One of: [reader, writer, accessor]
115
- # @param [Array<String>] attributes_ Attributes to define backend for
116
- # @param [Hash] options_ Backend options hash
117
- # @option options_ [Class] model_class Class of model
118
- # @option options_ [Boolean] cache (true) Enable cache for this model backend
119
- # @option options_ [Boolean] dirty Enable dirty tracking for this model
120
- # backend
121
- # @option options_ [Boolean, Hash] fallbacks Enable fallbacks or specify
122
- # fallbacks for this model backend
123
- # @option options_ [Boolean] fallthrough_accessors Enable fallthrough
124
- # locale accessors for this model backend
125
- # @option options_ [Boolean, Array<Symbol>] locale_accessors Enable locale
126
- # accessors or specify locales for which accessors should be defined on
127
- # this model backend. Will default to +true+ if +dirty+ option is +true+.
128
- # @option options_ [Boolean] presence (true) Enable presence filter on
129
- # reads and writes
127
+ # @param [Array<String>] attribute_names Names of attributes to define backend for
128
+ # @param [Hash] backend_options Backend options hash
129
+ # @option backend_options [Class] model_class Class of model
130
130
  # @raise [ArgumentError] if method is not reader, writer or accessor
131
- def initialize(method, *attributes_, **options_)
131
+ def initialize(*attribute_names, method: :accessor, backend: Mobility.default_backend, **backend_options)
132
132
  raise ArgumentError, "method must be one of: reader, writer, accessor" unless %i[reader writer accessor].include?(method)
133
- @options = options_
134
- @attributes = attributes_.map(&:to_s)
135
- model_class = options[:model_class]
136
- @backend_name = options.delete(:backend) || Mobility.config.default_backend
137
- @backend_class = Class.new(get_backend_class(backend: @backend_name,
138
- model_class: model_class))
139
- if (options[:dirty] && options[:fallthrough_accessors] != false)
140
- options[:fallthrough_accessors] = true
141
- end
142
- include FallthroughAccessors.new(*attributes) if options[:fallthrough_accessors]
133
+ @method = method
134
+ @options = Mobility.default_options.merge(backend_options)
135
+ @names = attribute_names.map(&:to_s)
136
+ raise Mobility::BackendRequired, "Backend option required if Mobility.config.default_backend is not set." if backend.nil?
137
+ @backend_name = backend
138
+ end
143
139
 
144
- @backend_class.configure(options) if @backend_class.respond_to?(:configure)
140
+ # Setup backend class, include modules into model class, add this
141
+ # attributes module to shared {Mobility::Wrapper} and setup model with
142
+ # backend setup block (see {Mobility::Backend::Setup#setup_model}).
143
+ # @param klass [Class] Class of model
144
+ def included(klass)
145
+ @model_class = @options[:model_class] = klass
146
+ @backend_class = Class.new(get_backend_class(backend_name).for(model_class))
145
147
 
146
- include_backend_modules(@backend_class, options)
148
+ @backend_class.configure(options) if @backend_class.respond_to?(:configure)
147
149
 
148
- @accessor_locales = options[:locale_accessors]
149
- @accessor_locales = Mobility.config.default_accessor_locales if @accessor_locales == true
150
- include LocaleAccessors.new(*attributes, locales: @accessor_locales) if @accessor_locales
150
+ Mobility.plugins.each do |name|
151
+ plugin = get_plugin_class(name)
152
+ plugin.apply(self, options[name])
153
+ end
151
154
 
152
- attributes.each do |attribute|
153
- define_backend(attribute)
154
- define_reader(attribute) if %i[accessor reader].include?(method)
155
- define_writer(attribute) if %i[accessor writer].include?(method)
155
+ names.each do |name|
156
+ define_backend(name)
157
+ define_reader(name) if %i[accessor reader].include?(method)
158
+ define_writer(name) if %i[accessor writer].include?(method)
156
159
  end
157
- end
158
160
 
159
- # Add this attributes module to shared {Mobility::Wrapper} and setup model
160
- # with backend setup block (see {Mobility::Backend::Setup#setup_model}).
161
- # @param model_class [Class] Class of model
162
- def included(model_class)
163
161
  model_class.mobility << self
164
- backend_class.setup_model(model_class, attributes, options)
162
+ backend_class.setup_model(model_class, names, options)
165
163
  end
166
164
 
167
- # Yield each attribute to block
168
- # @yield [String] Attribute
165
+ # Yield each attribute name to block
166
+ # @yieldparam [String] Attribute
169
167
  def each &block
170
- attributes.each(&block)
168
+ names.each(&block)
171
169
  end
172
170
 
173
171
  private
174
172
 
175
- # Include backend modules depending on value of options.
176
- def include_backend_modules(backend_class, options)
177
- backend_class.include(Backend::Cache) unless options[:cache] == false
178
- backend_class.include(Backend::Dirty.for(options[:model_class])) if options[:dirty]
179
- backend_class.include(Backend::Fallbacks) unless options[:fallbacks] == false
180
- backend_class.include(Backend::Presence) unless options[:presence] == false
181
- end
182
-
183
173
  def define_backend(attribute)
184
- _backend_class, _options = backend_class, options
174
+ backend_class_, options_ = backend_class, options
185
175
  define_method Backend.method_name(attribute) do
186
176
  @mobility_backends ||= {}
187
- @mobility_backends[attribute] ||= _backend_class.new(self, attribute, _options)
177
+ @mobility_backends[attribute] ||= backend_class_.new(self, attribute, options_)
188
178
  end
189
179
  end
190
180
 
191
181
  def define_reader(attribute)
192
182
  define_method attribute do |locale: Mobility.locale, **options|
183
+ return super() if options.delete(:super)
193
184
  Mobility.enforce_available_locales!(locale)
194
185
  mobility_backend_for(attribute).read(locale.to_sym, options)
195
186
  end
196
187
 
197
188
  define_method "#{attribute}?" do |locale: Mobility.locale, **options|
189
+ return super() if options.delete(:super)
198
190
  Mobility.enforce_available_locales!(locale)
199
- mobility_backend_for(attribute).read(locale.to_sym, options).present?
191
+ mobility_backend_for(attribute).present?(locale.to_sym, options)
200
192
  end
201
193
  end
202
194
 
203
195
  def define_writer(attribute)
204
196
  define_method "#{attribute}=" do |value, locale: Mobility.locale, **options|
197
+ return super(value) if options.delete(:super)
205
198
  Mobility.enforce_available_locales!(locale)
206
199
  mobility_backend_for(attribute).write(locale.to_sym, value, options)
207
200
  end
208
201
  end
209
202
 
210
- def get_backend_class(backend: nil, model_class: nil)
211
- raise Mobility::BackendRequired, "Backend option required if Mobility.config.default_backend is not set." if backend.nil?
212
- klass = Module === backend ? backend : Mobility::Backend.const_get(backend.to_s.camelize.gsub(/\s+/, ''.freeze).freeze)
213
- model_class.nil? ? klass : klass.for(model_class)
203
+ def get_backend_class(backend)
204
+ return backend if Module === backend
205
+ require "mobility/backends/#{backend}"
206
+ get_class_from_key(Mobility::Backends, backend)
207
+ end
208
+
209
+ def get_plugin_class(plugin)
210
+ require "mobility/plugins/#{plugin}"
211
+ get_class_from_key(Mobility::Plugins, plugin)
212
+ end
213
+
214
+ def get_class_from_key(parent_class, key)
215
+ klass_name = key.to_s.gsub(/(^|_)(.)/){|x| x[-1..-1].upcase}
216
+ parent_class.const_get(klass_name)
214
217
  end
215
218
  end
216
219
  end