mobility 0.1.20 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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