diff --git a/lib/mobility.rb b/lib/mobility.rb index d315324a9..2293ad57d 100644 --- a/lib/mobility.rb +++ b/lib/mobility.rb @@ -32,14 +32,14 @@ class MyClass =end module Mobility - autoload :Attributes, "mobility/attributes" - autoload :Backend, "mobility/backend" - autoload :BackendResetter, "mobility/backend_resetter" - autoload :Configuration, "mobility/configuration" - autoload :FallthroughAccessors, "mobility/fallthrough_accessors" - autoload :LocaleAccessors, "mobility/locale_accessors" - autoload :Translates, "mobility/translates" - autoload :Wrapper, "mobility/wrapper" + autoload :Attributes, "mobility/attributes" + autoload :Backend, "mobility/backend" + autoload :Backends, "mobility/backends" + autoload :BackendResetter, "mobility/backend_resetter" + autoload :Configuration, "mobility/configuration" + autoload :Plugins, "mobility/plugins" + autoload :Translates, "mobility/translates" + autoload :Wrapper, "mobility/wrapper" require "mobility/orm" @@ -159,12 +159,12 @@ def config # (see Mobility::Configuration#default_options) # @!method default_options # - # (see Mobility::Configuration#option_modules) - # @!method option_modules + # (see Mobility::Configuration#plugins) + # @!method plugins # # (see Mobility::Configuration#default_accessor_locales) # @!method default_accessor_locales - %w[accessor_method query_method default_backend default_options option_modules default_accessor_locales].each do |method_name| + %w[accessor_method query_method default_backend default_options plugins default_accessor_locales].each do |method_name| define_method method_name do config.public_send(method_name) end diff --git a/lib/mobility/active_record/model_translation.rb b/lib/mobility/active_record/model_translation.rb index 4c16d9909..f3e878eb8 100644 --- a/lib/mobility/active_record/model_translation.rb +++ b/lib/mobility/active_record/model_translation.rb @@ -3,7 +3,7 @@ module ActiveRecord =begin Subclassed dynamically to generate translation class in -{Backend::ActiveRecord::Table} backend. +{Backends::ActiveRecord::Table} backend. =end class ModelTranslation < ::ActiveRecord::Base diff --git a/lib/mobility/attributes.rb b/lib/mobility/attributes.rb index d061f6ca2..9482874bc 100644 --- a/lib/mobility/attributes.rb +++ b/lib/mobility/attributes.rb @@ -21,9 +21,10 @@ module Mobility Module.new do def title_backend - # Create a subclass of Mobility::Backend::MyBackend and include in it: - # - Mobility::Cache (from the cache: true option) - # - Mobility::Fallbacks (from the fallbacks: true option) + # Create a subclass of Mobility::Backends::MyBackend and include in it: + # - Mobility::Plugins::Cache (from the +cache: true+ option) + # - Mobility::Plugins::Fallbacks (from the +fallbacks: true+ option) + # - Mobility::Plugins::Presence (by default, disabled by +presence: false+) # Then instantiate the backend, memoize it, and return it. end @@ -81,8 +82,8 @@ def title_ja=(value) will be called when {Attributes} is {#included} in the model class, passed attributes and options defined when the backend was defined on the model class. This allows a backend to do things like (for example) define associations on a -model class required by the backend, as happens in the {Backend::KeyValue} and -{Backend::Table} backends. +model class required by the backend, as happens in the {Backends::KeyValue} and +{Backends::Table} backends. The +setup+ block is also used to extend the query scope/dataset (+i18n+ by default) with backend-specific query method support. @@ -139,13 +140,13 @@ def initialize(method, *attribute_names, backend: Mobility.default_backend, **ba # @param klass [Class] Class of model def included(klass) @model_class = @options[:model_class] = klass - @backend_class = Class.new(get_backend_class(backend: backend_name, - model_class: model_class)) + @backend_class = Class.new(get_backend_class(backend_name).for(model_class)) @backend_class.configure(options) if @backend_class.respond_to?(:configure) - Mobility.option_modules.each do |key, option_module| - option_module.apply(self, options[key]) + Mobility.plugins.each do |name| + plugin = get_plugin_class(name) + plugin.apply(self, options[name]) end names.each do |name| @@ -196,9 +197,17 @@ def define_writer(attribute) end end - def get_backend_class(backend: nil, model_class: nil) - klass = Module === backend ? backend : Mobility::Backend.const_get(backend.to_s.camelize.gsub(/\s+/, ''.freeze).freeze) - klass.for(model_class) + def get_backend_class(backend) + Module === backend ? backend : get_class_from_key(Mobility::Backends, backend) + end + + def get_plugin_class(name) + get_class_from_key(Mobility::Plugins, name) + end + + def get_class_from_key(parent_class, key) + klass_name = key.to_s.gsub(/(^|_)(.)/){|x| x[-1..-1].upcase} + parent_class.const_get(klass_name) end end end diff --git a/lib/mobility/backend.rb b/lib/mobility/backend.rb index efb4cfd2c..6ac3f4863 100644 --- a/lib/mobility/backend.rb +++ b/lib/mobility/backend.rb @@ -49,25 +49,8 @@ def self.configure(options) =end module Backend - autoload :ActiveModel, 'mobility/backend/active_model' - autoload :ActiveRecord, 'mobility/backend/active_record' - autoload :Cache, 'mobility/backend/cache' - autoload :Column, 'mobility/backend/column' - autoload :Default, 'mobility/backend/default' - autoload :Dirty, 'mobility/backend/dirty' - autoload :Fallbacks, 'mobility/backend/fallbacks' - autoload :HashValued, 'mobility/backend/hash_valued' - autoload :Hstore, 'mobility/backend/hstore' - autoload :Jsonb, 'mobility/backend/jsonb' - autoload :KeyValue, 'mobility/backend/key_value' - autoload :Null, 'mobility/backend/null' autoload :OrmDelegator, 'mobility/backend/orm_delegator' - autoload :Presence, 'mobility/backend/presence' - autoload :Sequel, 'mobility/backend/sequel' - autoload :Serialized, 'mobility/backend/serialized' autoload :StringifyLocale, 'mobility/backend/stringify_locale' - autoload :Table, 'mobility/backend/table' - autoload :TranslationCacher, 'mobility/backend/translation_cacher' # @return [String] Backend attribute attr_reader :attribute @@ -147,12 +130,12 @@ def for(_) self end - # Called from option modules to apply custom processing for this backend. - # Name is the name of the option module. - # @param [Symbol] name Name of option module - # @return [Boolean] Whether the module was applied - # @note This is currently only called by Backend::Cache. - def apply_module(_) + # Called from plugins to apply custom processing for this backend. + # Name is the name of the plugin. + # @param [Symbol] name Name of plugin + # @return [Boolean] Whether the plugin was applied + # @note This is currently only called by Plugins::Cache. + def apply_plugin(_) false end end diff --git a/lib/mobility/backend/active_model.rb b/lib/mobility/backend/active_model.rb deleted file mode 100644 index a800e381f..000000000 --- a/lib/mobility/backend/active_model.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Mobility - module Backend - module ActiveModel - autoload :Dirty, 'mobility/backend/active_model/dirty' - end - end -end diff --git a/lib/mobility/backend/active_record.rb b/lib/mobility/backend/active_record.rb deleted file mode 100644 index 5a8e32b90..000000000 --- a/lib/mobility/backend/active_record.rb +++ /dev/null @@ -1,29 +0,0 @@ -module Mobility - module Backend - module ActiveRecord - autoload :Column, 'mobility/backend/active_record/column' - autoload :Dirty, 'mobility/backend/active_record/dirty' - autoload :Hstore, 'mobility/backend/active_record/hstore' - autoload :Jsonb, 'mobility/backend/active_record/jsonb' - autoload :KeyValue, 'mobility/backend/active_record/key_value' - autoload :Serialized, 'mobility/backend/active_record/serialized' - autoload :QueryMethods, 'mobility/backend/active_record/query_methods' - autoload :Table, 'mobility/backend/active_record/table' - - def setup_query_methods(query_methods) - setup do |attributes, options| - extend(Module.new do - define_method ::Mobility.query_method do - super().extending(query_methods.new(attributes, options)) - end - end) - end - end - - def self.included(backend_class) - backend_class.include(Backend) - backend_class.extend(self) - end - end - end -end diff --git a/lib/mobility/backend/orm_delegator.rb b/lib/mobility/backend/orm_delegator.rb index 14757c105..de668756d 100644 --- a/lib/mobility/backend/orm_delegator.rb +++ b/lib/mobility/backend/orm_delegator.rb @@ -8,8 +8,8 @@ module Backend class Post < ActiveRecord::Base # ... end - Mobility::Backend::KeyValue.for(Post) - #=> Mobility::Backend::ActiveRecord::KeyValue + Mobility::Backends::KeyValue.for(Post) + #=> Mobility::Backends::ActiveRecord::KeyValue =end module OrmDelegator diff --git a/lib/mobility/backend/sequel.rb b/lib/mobility/backend/sequel.rb deleted file mode 100644 index c4b94cc88..000000000 --- a/lib/mobility/backend/sequel.rb +++ /dev/null @@ -1,29 +0,0 @@ -module Mobility - module Backend - module Sequel - autoload :Column, 'mobility/backend/sequel/column' - autoload :Dirty, 'mobility/backend/sequel/dirty' - autoload :Hstore, 'mobility/backend/sequel/hstore' - autoload :Jsonb, 'mobility/backend/sequel/jsonb' - autoload :KeyValue, 'mobility/backend/sequel/key_value' - autoload :Serialized, 'mobility/backend/sequel/serialized' - autoload :Table, 'mobility/backend/sequel/table' - autoload :QueryMethods, 'mobility/backend/sequel/query_methods' - - def setup_query_methods(query_methods) - setup do |attributes, options| - extend(Module.new do - define_method ::Mobility.query_method do - super().with_extend(query_methods.new(attributes, options)) - end - end) - end - end - - def self.included(backend_class) - backend_class.include(Backend) - backend_class.extend(self) - end - end - end -end diff --git a/lib/mobility/backend/translation_cacher.rb b/lib/mobility/backend/translation_cacher.rb deleted file mode 100644 index 6f29a20e1..000000000 --- a/lib/mobility/backend/translation_cacher.rb +++ /dev/null @@ -1,38 +0,0 @@ -module Mobility - module Backend -=begin - -Creates a module to cache a given translation fetch method. The cacher defines -private methods +cache+ and +clear_cache+ to access and clear, respectively, a -translations hash. - -This cacher is used to cache translation values in {Mobility::Backend::Cache}, -and also to cache translation *records* in {Mobility::Backend::Table} and -{Mobility::Backend::KeyValue}. - -=end - class TranslationCacher < Module - # @param [Symbol] fetch_method Name of translation fetch method to cache - def initialize(fetch_method) - define_method fetch_method do |locale, **options| - return super(locale, options) if options.delete(:cache) == false - if cache.has_key?(locale) - cache[locale] - else - cache[locale] = super(locale, options) - end - end - - define_method :cache do - @cache ||= {} - end - - define_method :clear_cache do - @cache = {} - end - - private :cache, :clear_cache - end - end - end -end diff --git a/lib/mobility/backends.rb b/lib/mobility/backends.rb new file mode 100644 index 000000000..1b9d4b8ec --- /dev/null +++ b/lib/mobility/backends.rb @@ -0,0 +1,14 @@ +module Mobility + module Backends + autoload :ActiveRecord, 'mobility/backends/active_record' + autoload :Column, 'mobility/backends/column' + autoload :HashValued, 'mobility/backends/hash_valued' + autoload :Hstore, 'mobility/backends/hstore' + autoload :Jsonb, 'mobility/backends/jsonb' + autoload :KeyValue, 'mobility/backends/key_value' + autoload :Null, 'mobility/backends/null' + autoload :Sequel, 'mobility/backends/sequel' + autoload :Serialized, 'mobility/backends/serialized' + autoload :Table, 'mobility/backends/table' + end +end diff --git a/lib/mobility/backends/active_record.rb b/lib/mobility/backends/active_record.rb new file mode 100644 index 000000000..24b970410 --- /dev/null +++ b/lib/mobility/backends/active_record.rb @@ -0,0 +1,28 @@ +module Mobility + module Backends + module ActiveRecord + autoload :Column, 'mobility/backends/active_record/column' + autoload :Hstore, 'mobility/backends/active_record/hstore' + autoload :Jsonb, 'mobility/backends/active_record/jsonb' + autoload :KeyValue, 'mobility/backends/active_record/key_value' + autoload :Serialized, 'mobility/backends/active_record/serialized' + autoload :QueryMethods, 'mobility/backends/active_record/query_methods' + autoload :Table, 'mobility/backends/active_record/table' + + def setup_query_methods(query_methods) + setup do |attributes, options| + extend(Module.new do + define_method ::Mobility.query_method do + super().extending(query_methods.new(attributes, options)) + end + end) + end + end + + def self.included(backend_class) + backend_class.include(Backend) + backend_class.extend(self) + end + end + end +end diff --git a/lib/mobility/backend/active_record/column.rb b/lib/mobility/backends/active_record/column.rb similarity index 87% rename from lib/mobility/backend/active_record/column.rb rename to lib/mobility/backends/active_record/column.rb index 423cd1812..1781c2016 100644 --- a/lib/mobility/backend/active_record/column.rb +++ b/lib/mobility/backends/active_record/column.rb @@ -1,8 +1,8 @@ module Mobility - module Backend + module Backends =begin -Implements the {Mobility::Backend::Column} backend for ActiveRecord models. +Implements the {Mobility::Backends::Column} backend for ActiveRecord models. You can use the +mobility:translations+ generator to create a migration adding translatable columns to the model table with: @@ -32,7 +32,7 @@ class ActiveRecord::Column include ActiveRecord include Column - require 'mobility/backend/active_record/column/query_methods' + require 'mobility/backends/active_record/column/query_methods' # @!group Backend Accessors # @!macro backend_reader diff --git a/lib/mobility/backend/active_record/column/query_methods.rb b/lib/mobility/backends/active_record/column/query_methods.rb similarity index 91% rename from lib/mobility/backend/active_record/column/query_methods.rb rename to lib/mobility/backends/active_record/column/query_methods.rb index 33771a961..b040b6e15 100644 --- a/lib/mobility/backend/active_record/column/query_methods.rb +++ b/lib/mobility/backends/active_record/column/query_methods.rb @@ -1,6 +1,6 @@ module Mobility - module Backend - class ActiveRecord::Column::QueryMethods < Backend::ActiveRecord::QueryMethods + module Backends + class ActiveRecord::Column::QueryMethods < ActiveRecord::QueryMethods def initialize(attributes, _) super attributes_extractor = @attributes_extractor diff --git a/lib/mobility/backend/active_record/hstore.rb b/lib/mobility/backends/active_record/hstore.rb similarity index 62% rename from lib/mobility/backend/active_record/hstore.rb rename to lib/mobility/backends/active_record/hstore.rb index 533150767..058cfa9a7 100644 --- a/lib/mobility/backend/active_record/hstore.rb +++ b/lib/mobility/backends/active_record/hstore.rb @@ -1,16 +1,16 @@ -require 'mobility/backend/active_record/pg_hash' +require 'mobility/backends/active_record/pg_hash' module Mobility - module Backend + module Backends =begin -Implements the {Mobility::Backend::Hstore} backend for ActiveRecord models. +Implements the {Mobility::Backends::Hstore} backend for ActiveRecord models. -@see Mobility::Backend::ActiveRecord::HashValued +@see Mobility::Backends::ActiveRecord::HashValued =end class ActiveRecord::Hstore < ActiveRecord::PgHash - require 'mobility/backend/active_record/hstore/query_methods' + require 'mobility/backends/active_record/hstore/query_methods' # @!group Backend Accessors # @!macro backend_reader diff --git a/lib/mobility/backend/active_record/hstore/query_methods.rb b/lib/mobility/backends/active_record/hstore/query_methods.rb similarity index 99% rename from lib/mobility/backend/active_record/hstore/query_methods.rb rename to lib/mobility/backends/active_record/hstore/query_methods.rb index 26ecaeef7..966be0298 100644 --- a/lib/mobility/backend/active_record/hstore/query_methods.rb +++ b/lib/mobility/backends/active_record/hstore/query_methods.rb @@ -1,5 +1,5 @@ module Mobility - module Backend + module Backends class ActiveRecord::Hstore::QueryMethods < ActiveRecord::QueryMethods def initialize(attributes, _) super diff --git a/lib/mobility/backend/active_record/jsonb.rb b/lib/mobility/backends/active_record/jsonb.rb similarity index 76% rename from lib/mobility/backend/active_record/jsonb.rb rename to lib/mobility/backends/active_record/jsonb.rb index 86fabe8ba..6d39d2429 100644 --- a/lib/mobility/backend/active_record/jsonb.rb +++ b/lib/mobility/backends/active_record/jsonb.rb @@ -1,16 +1,16 @@ -require 'mobility/backend/active_record/pg_hash' +require 'mobility/backends/active_record/pg_hash' module Mobility - module Backend + module Backends =begin -Implements the {Mobility::Backend::Jsonb} backend for ActiveRecord models. +Implements the {Mobility::Backends::Jsonb} backend for ActiveRecord models. -@see Mobility::Backend::ActiveRecord::HashValued +@see Mobility::Backends::ActiveRecord::HashValued =end class ActiveRecord::Jsonb < ActiveRecord::PgHash - require 'mobility/backend/active_record/jsonb/query_methods' + require 'mobility/backends/active_record/jsonb/query_methods' # @!group Backend Accessors # diff --git a/lib/mobility/backend/active_record/jsonb/query_methods.rb b/lib/mobility/backends/active_record/jsonb/query_methods.rb similarity index 99% rename from lib/mobility/backend/active_record/jsonb/query_methods.rb rename to lib/mobility/backends/active_record/jsonb/query_methods.rb index 091e974bb..e3ae46e28 100644 --- a/lib/mobility/backend/active_record/jsonb/query_methods.rb +++ b/lib/mobility/backends/active_record/jsonb/query_methods.rb @@ -1,5 +1,5 @@ module Mobility - module Backend + module Backends class ActiveRecord::Jsonb::QueryMethods < ActiveRecord::QueryMethods def initialize(attributes, _) super diff --git a/lib/mobility/backend/active_record/key_value.rb b/lib/mobility/backends/active_record/key_value.rb similarity index 95% rename from lib/mobility/backend/active_record/key_value.rb rename to lib/mobility/backends/active_record/key_value.rb index 7684679a8..da933024a 100644 --- a/lib/mobility/backend/active_record/key_value.rb +++ b/lib/mobility/backends/active_record/key_value.rb @@ -1,10 +1,10 @@ # frozen-string-literal: true module Mobility - module Backend + module Backends =begin -Implements the {Mobility::Backend::KeyValue} backend for ActiveRecord models. +Implements the {Mobility::Backends::KeyValue} backend for ActiveRecord models. @example class Post < ActiveRecord::Base @@ -24,7 +24,7 @@ class ActiveRecord::KeyValue include ActiveRecord include KeyValue - require 'mobility/backend/active_record/key_value/query_methods' + require 'mobility/backends/active_record/key_value/query_methods' # @!group Backend Configuration # @option options [Symbol] type (:text) Column type to use diff --git a/lib/mobility/backend/active_record/key_value/query_methods.rb b/lib/mobility/backends/active_record/key_value/query_methods.rb similarity index 99% rename from lib/mobility/backend/active_record/key_value/query_methods.rb rename to lib/mobility/backends/active_record/key_value/query_methods.rb index 670a0525c..7111eea66 100644 --- a/lib/mobility/backend/active_record/key_value/query_methods.rb +++ b/lib/mobility/backends/active_record/key_value/query_methods.rb @@ -1,5 +1,5 @@ module Mobility - module Backend + module Backends class ActiveRecord::KeyValue::QueryMethods < ActiveRecord::QueryMethods def initialize(attributes, association_name: nil, class_name: nil, **) super diff --git a/lib/mobility/backend/active_record/pg_hash.rb b/lib/mobility/backends/active_record/pg_hash.rb similarity index 97% rename from lib/mobility/backend/active_record/pg_hash.rb rename to lib/mobility/backends/active_record/pg_hash.rb index 810857051..59de1eca2 100644 --- a/lib/mobility/backend/active_record/pg_hash.rb +++ b/lib/mobility/backends/active_record/pg_hash.rb @@ -1,5 +1,5 @@ module Mobility - module Backend + module Backends =begin Internal class used by ActiveRecord backends backed by a Postgres data type diff --git a/lib/mobility/backend/active_record/query_methods.rb b/lib/mobility/backends/active_record/query_methods.rb similarity index 98% rename from lib/mobility/backend/active_record/query_methods.rb rename to lib/mobility/backends/active_record/query_methods.rb index 4092bff57..14f523ab4 100644 --- a/lib/mobility/backend/active_record/query_methods.rb +++ b/lib/mobility/backends/active_record/query_methods.rb @@ -1,5 +1,5 @@ module Mobility - module Backend + module Backends module ActiveRecord =begin diff --git a/lib/mobility/backend/active_record/serialized.rb b/lib/mobility/backends/active_record/serialized.rb similarity index 82% rename from lib/mobility/backend/active_record/serialized.rb rename to lib/mobility/backends/active_record/serialized.rb index 22fbbdd41..93aa761b6 100644 --- a/lib/mobility/backend/active_record/serialized.rb +++ b/lib/mobility/backends/active_record/serialized.rb @@ -1,8 +1,8 @@ module Mobility - module Backend + module Backends =begin -Implements {Mobility::Backend::Serialized} backend for ActiveRecord models. +Implements {Mobility::Backends::Serialized} backend for ActiveRecord models. @example Define attribute with serialized backend class Post < ActiveRecord::Base @@ -24,12 +24,12 @@ class ActiveRecord::Serialized include ActiveRecord include HashValued - require 'mobility/backend/active_record/serialized/query_methods' + require 'mobility/backends/active_record/serialized/query_methods' # @!group Backend Configuration - # @param (see Backend::Serialized.configure) - # @option (see Backend::Serialized.configure) - # @raise (see Backend::Serialized.configure) + # @param (see Backends::Serialized.configure) + # @option (see Backends::Serialized.configure) + # @raise (see Backends::Serialized.configure) def self.configure(options) Serialized.configure(options) end diff --git a/lib/mobility/backend/active_record/serialized/query_methods.rb b/lib/mobility/backends/active_record/serialized/query_methods.rb similarity index 85% rename from lib/mobility/backend/active_record/serialized/query_methods.rb rename to lib/mobility/backends/active_record/serialized/query_methods.rb index 23cc41166..3e082c7f2 100644 --- a/lib/mobility/backend/active_record/serialized/query_methods.rb +++ b/lib/mobility/backends/active_record/serialized/query_methods.rb @@ -1,10 +1,10 @@ module Mobility - module Backend + module Backends class ActiveRecord::Serialized::QueryMethods < ActiveRecord::QueryMethods def initialize(attributes, _) super attributes_extractor = @attributes_extractor - opts_checker = @opts_checker = Backend::Serialized.attr_checker(attributes_extractor) + opts_checker = @opts_checker = Backends::Serialized.attr_checker(attributes_extractor) define_method :where! do |opts, *rest| opts_checker.call(opts) || super(opts, *rest) diff --git a/lib/mobility/backend/active_record/table.rb b/lib/mobility/backends/active_record/table.rb similarity index 96% rename from lib/mobility/backend/active_record/table.rb rename to lib/mobility/backends/active_record/table.rb index ad1fcf615..2e62be287 100644 --- a/lib/mobility/backend/active_record/table.rb +++ b/lib/mobility/backends/active_record/table.rb @@ -1,10 +1,10 @@ # frozen-string-literal: true module Mobility - module Backend + module Backends =begin -Implements the {Mobility::Backend::Table} backend for ActiveRecord models. +Implements the {Mobility::Backends::Table} backend for ActiveRecord models. To generate a translation table for a model +Post+, you can use the included +mobility:translations+ generator: @@ -87,7 +87,7 @@ class ActiveRecord::Table include ActiveRecord include Table - require 'mobility/backend/active_record/table/query_methods' + require 'mobility/backends/active_record/table/query_methods' # @return [Symbol] name of the association method attr_reader :association_name diff --git a/lib/mobility/backend/active_record/table/query_methods.rb b/lib/mobility/backends/active_record/table/query_methods.rb similarity index 99% rename from lib/mobility/backend/active_record/table/query_methods.rb rename to lib/mobility/backends/active_record/table/query_methods.rb index 615a1134c..25b6ebce3 100644 --- a/lib/mobility/backend/active_record/table/query_methods.rb +++ b/lib/mobility/backends/active_record/table/query_methods.rb @@ -1,5 +1,5 @@ module Mobility - module Backend + module Backends class ActiveRecord::Table::QueryMethods < ActiveRecord::QueryMethods def initialize(attributes, association_name: nil, model_class: nil, subclass_name: nil, **options) super diff --git a/lib/mobility/backend/column.rb b/lib/mobility/backends/column.rb similarity index 88% rename from lib/mobility/backend/column.rb rename to lib/mobility/backends/column.rb index d4e90d65b..95a776986 100644 --- a/lib/mobility/backend/column.rb +++ b/lib/mobility/backends/column.rb @@ -1,5 +1,5 @@ module Mobility - module Backend + module Backends =begin Stores translated attribute as a column on the model table. To use this @@ -20,12 +20,12 @@ module Backend There are no options for this backend. Also, the +locale_accessors+ option will be ignored if set, since it would cause a conflict with column accessors. -@see Mobility::Backend::ActiveRecord::Column -@see Mobility::Backend::Sequel::Column +@see Mobility::Backends::ActiveRecord::Column +@see Mobility::Backends::Sequel::Column =end module Column - extend OrmDelegator + extend Backend::OrmDelegator # Returns name of column where translated attribute is stored # @param [Symbol] locale @@ -44,7 +44,7 @@ def self.column_name_for(attribute, locale = Mobility.locale) end def self.included(base) - base.extend OrmDelegator + base.extend Backend::OrmDelegator end end end diff --git a/lib/mobility/backend/hash_valued.rb b/lib/mobility/backends/hash_valued.rb similarity index 96% rename from lib/mobility/backend/hash_valued.rb rename to lib/mobility/backends/hash_valued.rb index ce5c6d5f7..c0c7e1064 100644 --- a/lib/mobility/backend/hash_valued.rb +++ b/lib/mobility/backends/hash_valued.rb @@ -1,5 +1,5 @@ module Mobility - module Backend + module Backends =begin Defines read and write methods that access the value at a key with value diff --git a/lib/mobility/backend/hstore.rb b/lib/mobility/backends/hstore.rb similarity index 66% rename from lib/mobility/backend/hstore.rb rename to lib/mobility/backends/hstore.rb index 0493585ed..fa0260553 100644 --- a/lib/mobility/backend/hstore.rb +++ b/lib/mobility/backends/hstore.rb @@ -1,5 +1,5 @@ module Mobility - module Backend + module Backends =begin @@ -9,13 +9,13 @@ module Backend This backend has no options. -@see Mobility::Backend::ActiveRecord::Hstore -@see Mobility::Backend::Sequel::Hstore +@see Mobility::Backends::ActiveRecord::Hstore +@see Mobility::Backends::Sequel::Hstore @see https://www.postgresql.org/docs/current/static/hstore.html PostgreSQL Documentation for hstore =end module Hstore - extend OrmDelegator + extend Backend::OrmDelegator end end end diff --git a/lib/mobility/backend/jsonb.rb b/lib/mobility/backends/jsonb.rb similarity index 67% rename from lib/mobility/backend/jsonb.rb rename to lib/mobility/backends/jsonb.rb index a4f313d0f..a5094f87c 100644 --- a/lib/mobility/backend/jsonb.rb +++ b/lib/mobility/backends/jsonb.rb @@ -1,5 +1,5 @@ module Mobility - module Backend + module Backends =begin @@ -9,13 +9,13 @@ module Backend This backend has no options. -@see Mobility::Backend::ActiveRecord::Jsonb -@see Mobility::Backend::Sequel::Jsonb +@see Mobility::Backends::ActiveRecord::Jsonb +@see Mobility::Backends::Sequel::Jsonb @see https://www.postgresql.org/docs/current/static/datatype-json.html PostgreSQL Documentation for JSON Types =end module Jsonb - extend OrmDelegator + extend Backend::OrmDelegator end end end diff --git a/lib/mobility/backend/key_value.rb b/lib/mobility/backends/key_value.rb similarity index 87% rename from lib/mobility/backend/key_value.rb rename to lib/mobility/backends/key_value.rb index 424028665..a800c8c73 100644 --- a/lib/mobility/backend/key_value.rb +++ b/lib/mobility/backends/key_value.rb @@ -1,5 +1,5 @@ module Mobility - module Backend + module Backends =begin Stores attribute translation as attribute/value pair on a shared translations @@ -35,12 +35,12 @@ module Backend for Sequel models). If string is passed in, it will be constantized to get the class. -@see Mobility::Backend::ActiveRecord::KeyValue -@see Mobility::Backend::Sequel::KeyValue +@see Mobility::Backends::ActiveRecord::KeyValue +@see Mobility::Backends::Sequel::KeyValue =end module KeyValue - extend OrmDelegator + extend Backend::OrmDelegator # @return [Symbol] name of the association attr_reader :association_name @@ -77,10 +77,10 @@ def configure(options) raise ArgumentError, "type must be one of: [text, string]" unless [:text, :string].include?(options[:type]) end - # Apply custom processing for option module - # @param (see Backend::Setup#apply_module) - # @return (see Backend::Setup#apply_module) - def apply_module(name) + # Apply custom processing for plugin + # @param (see Backend::Setup#apply_plugin) + # @return (see Backend::Setup#apply_plugin) + def apply_plugin(name) if name == :cache include Cache true @@ -91,7 +91,7 @@ def apply_module(name) end module Cache - include TranslationCacher.new(:translation_for) + include Plugins::Cache::TranslationCacher.new(:translation_for) end end end diff --git a/lib/mobility/backend/null.rb b/lib/mobility/backends/null.rb similarity index 95% rename from lib/mobility/backend/null.rb rename to lib/mobility/backends/null.rb index 921f78fa2..a19f05391 100644 --- a/lib/mobility/backend/null.rb +++ b/lib/mobility/backends/null.rb @@ -1,5 +1,5 @@ module Mobility - module Backend + module Backends =begin Backend which does absolutely nothing. Mostly for testing purposes. diff --git a/lib/mobility/backends/sequel.rb b/lib/mobility/backends/sequel.rb new file mode 100644 index 000000000..0c325ab92 --- /dev/null +++ b/lib/mobility/backends/sequel.rb @@ -0,0 +1,28 @@ +module Mobility + module Backends + module Sequel + autoload :Column, 'mobility/backends/sequel/column' + autoload :Hstore, 'mobility/backends/sequel/hstore' + autoload :Jsonb, 'mobility/backends/sequel/jsonb' + autoload :KeyValue, 'mobility/backends/sequel/key_value' + autoload :Serialized, 'mobility/backends/sequel/serialized' + autoload :Table, 'mobility/backends/sequel/table' + autoload :QueryMethods, 'mobility/backends/sequel/query_methods' + + def setup_query_methods(query_methods) + setup do |attributes, options| + extend(Module.new do + define_method ::Mobility.query_method do + super().with_extend(query_methods.new(attributes, options)) + end + end) + end + end + + def self.included(backend_class) + backend_class.include(Backend) + backend_class.extend(self) + end + end + end +end diff --git a/lib/mobility/backend/sequel/column.rb b/lib/mobility/backends/sequel/column.rb similarity index 81% rename from lib/mobility/backend/sequel/column.rb rename to lib/mobility/backends/sequel/column.rb index 7a0bfedbb..bfe433735 100644 --- a/lib/mobility/backend/sequel/column.rb +++ b/lib/mobility/backends/sequel/column.rb @@ -1,8 +1,8 @@ module Mobility - module Backend + module Backends =begin -Implements the {Mobility::Backend::Column} backend for Sequel models. +Implements the {Mobility::Backends::Column} backend for Sequel models. @note This backend disables the +locale_accessors+ option, which would otherwise interfere with column methods. @@ -11,7 +11,7 @@ class Sequel::Column include Sequel include Column - require 'mobility/backend/sequel/column/query_methods' + require 'mobility/backends/sequel/column/query_methods' # @!group Backend Accessors # @!macro backend_reader diff --git a/lib/mobility/backend/sequel/column/query_methods.rb b/lib/mobility/backends/sequel/column/query_methods.rb similarity index 89% rename from lib/mobility/backend/sequel/column/query_methods.rb rename to lib/mobility/backends/sequel/column/query_methods.rb index d4278bb95..56cba67a2 100644 --- a/lib/mobility/backend/sequel/column/query_methods.rb +++ b/lib/mobility/backends/sequel/column/query_methods.rb @@ -1,6 +1,6 @@ module Mobility - module Backend - class Sequel::Column::QueryMethods < Backend::Sequel::QueryMethods + module Backends + class Sequel::Column::QueryMethods < Sequel::QueryMethods def initialize(attributes, _) super attributes_extractor = @attributes_extractor diff --git a/lib/mobility/backend/sequel/hstore.rb b/lib/mobility/backends/sequel/hstore.rb similarity index 64% rename from lib/mobility/backend/sequel/hstore.rb rename to lib/mobility/backends/sequel/hstore.rb index c2110e36d..caf938469 100644 --- a/lib/mobility/backend/sequel/hstore.rb +++ b/lib/mobility/backends/sequel/hstore.rb @@ -1,16 +1,16 @@ -require 'mobility/backend/sequel/pg_hash' +require 'mobility/backends/sequel/pg_hash' module Mobility - module Backend + module Backends =begin -Implements the {Mobility::Backend::Hstore} backend for Sequel models. +Implements the {Mobility::Backends::Hstore} backend for Sequel models. -@see Mobility::Backend::Sequel::HashValued +@see Mobility::Backends::Sequel::HashValued =end class Sequel::Hstore < Sequel::PgHash - require 'mobility/backend/sequel/hstore/query_methods' + require 'mobility/backends/sequel/hstore/query_methods' # @!group Backend Accessors # @!macro backend_reader diff --git a/lib/mobility/backend/sequel/hstore/query_methods.rb b/lib/mobility/backends/sequel/hstore/query_methods.rb similarity index 88% rename from lib/mobility/backend/sequel/hstore/query_methods.rb rename to lib/mobility/backends/sequel/hstore/query_methods.rb index 50a4f3001..d03fa2013 100644 --- a/lib/mobility/backend/sequel/hstore/query_methods.rb +++ b/lib/mobility/backends/sequel/hstore/query_methods.rb @@ -1,9 +1,9 @@ -require 'mobility/backend/sequel/postgres_query_methods' +require 'mobility/backends/sequel/postgres_query_methods' Sequel.extension :pg_hstore, :pg_hstore_ops module Mobility - module Backend + module Backends class Sequel::Hstore::QueryMethods < Sequel::QueryMethods include PostgresQueryMethods diff --git a/lib/mobility/backend/sequel/jsonb.rb b/lib/mobility/backends/sequel/jsonb.rb similarity index 78% rename from lib/mobility/backend/sequel/jsonb.rb rename to lib/mobility/backends/sequel/jsonb.rb index 6a857e21d..c015c3599 100644 --- a/lib/mobility/backend/sequel/jsonb.rb +++ b/lib/mobility/backends/sequel/jsonb.rb @@ -1,16 +1,16 @@ -require 'mobility/backend/sequel/pg_hash' +require 'mobility/backends/sequel/pg_hash' module Mobility - module Backend + module Backends =begin -Implements the {Mobility::Backend::Jsonb} backend for Sequel models. +Implements the {Mobility::Backends::Jsonb} backend for Sequel models. -@see Mobility::Backend::Sequel::HashValued +@see Mobility::Backends::Sequel::HashValued =end class Sequel::Jsonb < Sequel::PgHash - require 'mobility/backend/sequel/jsonb/query_methods' + require 'mobility/backends/sequel/jsonb/query_methods' # @!group Backend Accessors # diff --git a/lib/mobility/backend/sequel/jsonb/query_methods.rb b/lib/mobility/backends/sequel/jsonb/query_methods.rb similarity index 87% rename from lib/mobility/backend/sequel/jsonb/query_methods.rb rename to lib/mobility/backends/sequel/jsonb/query_methods.rb index 623f64afb..0d2fda320 100644 --- a/lib/mobility/backend/sequel/jsonb/query_methods.rb +++ b/lib/mobility/backends/sequel/jsonb/query_methods.rb @@ -1,9 +1,9 @@ -require 'mobility/backend/sequel/postgres_query_methods' +require 'mobility/backends/sequel/postgres_query_methods' Sequel.extension :pg_json, :pg_json_ops module Mobility - module Backend + module Backends class Sequel::Jsonb::QueryMethods < Sequel::QueryMethods include PostgresQueryMethods diff --git a/lib/mobility/backend/sequel/key_value.rb b/lib/mobility/backends/sequel/key_value.rb similarity index 96% rename from lib/mobility/backend/sequel/key_value.rb rename to lib/mobility/backends/sequel/key_value.rb index d79334cd3..eb287e188 100644 --- a/lib/mobility/backend/sequel/key_value.rb +++ b/lib/mobility/backends/sequel/key_value.rb @@ -1,10 +1,10 @@ # frozen-string-literal: true module Mobility - module Backend + module Backends =begin -Implements the {Mobility::Backend::KeyValue} backend for Sequel models. +Implements the {Mobility::Backends::KeyValue} backend for Sequel models. @note This backend requires the cache to be enabled in order to track and store changed translations, since Sequel does not support +build+-type @@ -15,7 +15,7 @@ class Sequel::KeyValue include Sequel include KeyValue - require 'mobility/backend/sequel/key_value/query_methods' + require 'mobility/backends/sequel/key_value/query_methods' # @return [Class] translation model class attr_reader :class_name diff --git a/lib/mobility/backend/sequel/key_value/query_methods.rb b/lib/mobility/backends/sequel/key_value/query_methods.rb similarity index 99% rename from lib/mobility/backend/sequel/key_value/query_methods.rb rename to lib/mobility/backends/sequel/key_value/query_methods.rb index 59ae0bb4e..4828d0585 100644 --- a/lib/mobility/backend/sequel/key_value/query_methods.rb +++ b/lib/mobility/backends/sequel/key_value/query_methods.rb @@ -1,5 +1,5 @@ module Mobility - module Backend + module Backends class Sequel::KeyValue::QueryMethods < Sequel::QueryMethods def initialize(attributes, association_name: nil, class_name: nil, **) super diff --git a/lib/mobility/backend/sequel/pg_hash.rb b/lib/mobility/backends/sequel/pg_hash.rb similarity index 97% rename from lib/mobility/backend/sequel/pg_hash.rb rename to lib/mobility/backends/sequel/pg_hash.rb index 8a2ed197e..50f14672b 100644 --- a/lib/mobility/backend/sequel/pg_hash.rb +++ b/lib/mobility/backends/sequel/pg_hash.rb @@ -1,5 +1,5 @@ module Mobility - module Backend + module Backends =begin Internal class used by Sequel backends backed by a Postgres data type (hstore, diff --git a/lib/mobility/backend/sequel/postgres_query_methods.rb b/lib/mobility/backends/sequel/postgres_query_methods.rb similarity index 98% rename from lib/mobility/backend/sequel/postgres_query_methods.rb rename to lib/mobility/backends/sequel/postgres_query_methods.rb index 59236ec95..2e4bb8944 100644 --- a/lib/mobility/backend/sequel/postgres_query_methods.rb +++ b/lib/mobility/backends/sequel/postgres_query_methods.rb @@ -1,6 +1,6 @@ module Mobility - module Backend + module Backends module PostgresQueryMethods private diff --git a/lib/mobility/backend/sequel/query_methods.rb b/lib/mobility/backends/sequel/query_methods.rb similarity index 96% rename from lib/mobility/backend/sequel/query_methods.rb rename to lib/mobility/backends/sequel/query_methods.rb index bb337d4da..172e00a75 100644 --- a/lib/mobility/backend/sequel/query_methods.rb +++ b/lib/mobility/backends/sequel/query_methods.rb @@ -1,5 +1,5 @@ module Mobility - module Backend + module Backends module Sequel =begin diff --git a/lib/mobility/backend/sequel/serialized.rb b/lib/mobility/backends/sequel/serialized.rb similarity index 90% rename from lib/mobility/backend/sequel/serialized.rb rename to lib/mobility/backends/sequel/serialized.rb index 2e597995d..d7b86bbef 100644 --- a/lib/mobility/backend/sequel/serialized.rb +++ b/lib/mobility/backends/sequel/serialized.rb @@ -1,8 +1,8 @@ module Mobility - module Backend + module Backends =begin -Implements {Mobility::Backend::Serialized} backend for Sequel models, using the +Implements {Mobility::Backends::Serialized} backend for Sequel models, using the Sequel serialization plugin. @see http://sequel.jeremyevans.net/rdoc-plugins/classes/Sequel/Plugins/Serialization.html Sequel serialization plugin @@ -31,12 +31,12 @@ class Sequel::Serialized include Sequel include HashValued - require 'mobility/backend/sequel/serialized/query_methods' + require 'mobility/backends/sequel/serialized/query_methods' # @!group Backend Configuration - # @param (see Backend::Serialized.configure) - # @option (see Backend::Serialized.configure) - # @raise (see Backend::Serialized.configure) + # @param (see Backends::Serialized.configure) + # @option (see Backends::Serialized.configure) + # @raise (see Backends::Serialized.configure) def self.configure(options) Serialized.configure(options) end diff --git a/lib/mobility/backend/sequel/serialized/query_methods.rb b/lib/mobility/backends/sequel/serialized/query_methods.rb similarity index 77% rename from lib/mobility/backend/sequel/serialized/query_methods.rb rename to lib/mobility/backends/sequel/serialized/query_methods.rb index 672ecbdde..4d35bf9e6 100644 --- a/lib/mobility/backend/sequel/serialized/query_methods.rb +++ b/lib/mobility/backends/sequel/serialized/query_methods.rb @@ -1,10 +1,10 @@ module Mobility - module Backend + module Backends class Sequel::Serialized::QueryMethods < Sequel::QueryMethods def initialize(attributes, _) super attributes_extractor = @attributes_extractor - cond_checker = Backend::Serialized.attr_checker(attributes_extractor) + cond_checker = Backends::Serialized.attr_checker(attributes_extractor) define_method :where do |*cond, &block| cond_checker.call(cond.first) || super(*cond, &block) diff --git a/lib/mobility/backend/sequel/table.rb b/lib/mobility/backends/sequel/table.rb similarity index 95% rename from lib/mobility/backend/sequel/table.rb rename to lib/mobility/backends/sequel/table.rb index 4da4be5af..fded5d58d 100644 --- a/lib/mobility/backend/sequel/table.rb +++ b/lib/mobility/backends/sequel/table.rb @@ -1,15 +1,15 @@ module Mobility - module Backend + module Backends =begin -Implements the {Mobility::Backend::Table} backend for Sequel models. +Implements the {Mobility::Backends::Table} backend for Sequel models. =end class Sequel::Table include Sequel include Table - require 'mobility/backend/sequel/table/query_methods' + require 'mobility/backends/sequel/table/query_methods' # @return [Symbol] name of the association method attr_reader :association_name diff --git a/lib/mobility/backend/sequel/table/query_methods.rb b/lib/mobility/backends/sequel/table/query_methods.rb similarity index 99% rename from lib/mobility/backend/sequel/table/query_methods.rb rename to lib/mobility/backends/sequel/table/query_methods.rb index 4d1596f88..aede042ac 100644 --- a/lib/mobility/backend/sequel/table/query_methods.rb +++ b/lib/mobility/backends/sequel/table/query_methods.rb @@ -1,5 +1,5 @@ module Mobility - module Backend + module Backends class Sequel::Table::QueryMethods < Sequel::QueryMethods def initialize(attributes, association_name: nil, model_class: nil, subclass_name: nil, **options) super diff --git a/lib/mobility/backend/serialized.rb b/lib/mobility/backends/serialized.rb similarity index 93% rename from lib/mobility/backend/serialized.rb rename to lib/mobility/backends/serialized.rb index 7ba8de318..8a3683ddf 100644 --- a/lib/mobility/backend/serialized.rb +++ b/lib/mobility/backends/serialized.rb @@ -1,5 +1,5 @@ module Mobility - module Backend + module Backends =begin Stores translations as serialized attributes in a single text column. This @@ -15,12 +15,12 @@ module Backend Format for serialization. Either +:yaml+ (default) or +:json+. -@see Mobility::Backend::ActiveRecord::Serialized -@see Mobility::Backend::Sequel::Serialized +@see Mobility::Backends::ActiveRecord::Serialized +@see Mobility::Backends::Sequel::Serialized =end module Serialized - extend OrmDelegator + extend Backend::OrmDelegator class << self diff --git a/lib/mobility/backend/table.rb b/lib/mobility/backends/table.rb similarity index 89% rename from lib/mobility/backend/table.rb rename to lib/mobility/backends/table.rb index e7c40a414..02b275061 100644 --- a/lib/mobility/backend/table.rb +++ b/lib/mobility/backends/table.rb @@ -1,5 +1,5 @@ module Mobility - module Backend + module Backends =begin Stores attribute translation as rows on a model-specific translation table @@ -30,7 +30,7 @@ module Backend used in this case will be generated from the +association_name+ by singularizing it and converting it to camelcase. -For more details, see examples in {Mobility::Backend::ActiveRecord::Table}. +For more details, see examples in {Mobility::Backends::ActiveRecord::Table}. ==Backend Options @@ -58,11 +58,11 @@ module Backend default +:Translation+. Should be a symbol. Generally this does not need to be set. -@see Mobility::Backend::ActiveRecord::Table -@see Mobility::Backend::Sequel::Table +@see Mobility::Backends::ActiveRecord::Table +@see Mobility::Backends::Sequel::Table =end module Table - extend OrmDelegator + extend Backend::OrmDelegator # @!macro backend_constructor # @option options [Symbol] association_name Name of association @@ -88,10 +88,10 @@ def self.included(backend) end module ClassMethods - # Apply custom processing for option module - # @param (see Backend::Setup#apply_module) - # @return (see Backend::Setup#apply_module) - def apply_module(name) + # Apply custom processing for plugin + # @param (see Backend::Setup#apply_plugin) + # @return (see Backend::Setup#apply_plugin) + def apply_plugin(name) if name == :cache include Cache true @@ -104,7 +104,7 @@ def apply_module(name) # Simple hash cache to memoize translations as a hash so they can be # fetched quickly. module Cache - include TranslationCacher.new(:translation_for) + include Plugins::Cache::TranslationCacher.new(:translation_for) private diff --git a/lib/mobility/configuration.rb b/lib/mobility/configuration.rb index de7bb328c..1cffe7543 100644 --- a/lib/mobility/configuration.rb +++ b/lib/mobility/configuration.rb @@ -29,12 +29,11 @@ def default_options=(options) end end - # Option modules to apply. Defines which module to apply for each option - # key. Order of hash keys/values is important, as this becomes the order in - # which modules are applied and included into the backend class or + # Plugins to apply. Order of plugins is important, as this becomes the + # order in which plugins modules are included into the backend class or # attributes instance. - # @return [Hash] - attr_accessor :option_modules + # @return [Array] + attr_accessor :plugins # Default fallbacks instance # @return [I18n::Locale::Fallbacks] @@ -71,15 +70,15 @@ def initialize presence: true, default: nil } - @option_modules = { - cache: Backend::Cache, - dirty: Backend::Dirty, - fallbacks: Backend::Fallbacks, - presence: Backend::Presence, - default: Backend::Default, - fallthrough_accessors: FallthroughAccessors, - locale_accessors: LocaleAccessors - } + @plugins = %i[ + cache + dirty + fallbacks + presence + default + fallthrough_accessors + locale_accessors + ] end class ReservedOptionKey < Exception; end diff --git a/lib/mobility/fallthrough_accessors.rb b/lib/mobility/fallthrough_accessors.rb deleted file mode 100644 index a7fa28750..000000000 --- a/lib/mobility/fallthrough_accessors.rb +++ /dev/null @@ -1,64 +0,0 @@ -# frozen-string-literal: true - -module Mobility -=begin - -Defines +method_missing+ and +respond_to_missing?+ methods for a set of -attributes such that a method call using a locale accessor, like: - - article.title_pt_br - -will return the value of +article.title+ with the locale set to +pt-BR+ around -the method call. The class is called "FallthroughAccessors" because when -included in a model class, locale-specific methods will be available even if -not explicitly defined with the +locale_accessors+ option. - -This is a less efficient (but more open-ended) implementation of locale -accessors, for use in cases where the locales to be used are not known when the -model class is generated. - -@example Using fallthrough locales on a plain old ruby class - class Post - def title - "title in #{Mobility.locale}" - end - include Mobility::FallthroughAccessors.new("title") - end - - Mobility.locale = :en - post = Post.new - post.title - #=> "title in en" - post.title_fr - #=> "title in fr" - -=end - class FallthroughAccessors < Module - # Apply fallthrough accessors option module to attributes. - # @param [Attributes] attributes - # @param [Boolean] option - def self.apply(attributes, option) - attributes.model_class.include new(*attributes.names) if option - end - - # @param [String] One or more attributes - def initialize(*attributes) - method_name_regex = /\A(#{attributes.join('|'.freeze)})_([a-z]{2}(_[a-z]{2})?)(=?|\??)\z/.freeze - - define_method :method_missing do |method_name, *arguments, &block| - if method_name =~ method_name_regex - attribute = $1.to_sym - locale, suffix = $2.split('_'.freeze) - locale = "#{locale}-#{suffix.upcase}".freeze if suffix - Mobility.with_locale(locale) { public_send("#{attribute}#{$4}".freeze, *arguments) } - else - super(method_name, *arguments, &block) - end - end - - define_method :respond_to_missing? do |method_name, include_private = false| - (method_name =~ method_name_regex) || super(method_name, include_private) - end - end - end -end diff --git a/lib/mobility/locale_accessors.rb b/lib/mobility/locale_accessors.rb deleted file mode 100644 index 42333cd8e..000000000 --- a/lib/mobility/locale_accessors.rb +++ /dev/null @@ -1,82 +0,0 @@ -# frozen-string-literal: true - -module Mobility -=begin - -Defines methods for a set of locales to access translated attributes in those -locales directly with a method call, using a suffix including the locale: - - article.title_pt_br - -If no locales are passed as an option to the initializer, -+I18n.available_locales+ will be used by default. - -@example - class Post - def title - "title in #{Mobility.locale}" - end - include Mobility::LocaleAccessors.new("title", locales: [:en, :fr]) - end - - Mobility.locale = :en - post = Post.new - post.title - #=> "title in en" - post.title_fr - #=> "title in fr" - -=end - class LocaleAccessors < Module - # Apply locale accessors option module to attributes. - # @param [Attributes] attributes - # @param [Boolean] option - def self.apply(attributes, option) - if accessor_locales = option - accessor_locales = Mobility.config.default_accessor_locales if accessor_locales == true - attributes.model_class.include new(*attributes.names, locales: accessor_locales) - end - end - - # @param [String] One or more attribute names - # @param [Array] Locales - def initialize(*attribute_names, locales: I18n.available_locales) - attribute_names.each do |name| - locales.each do |locale| - define_reader(name, locale) - define_writer(name, locale) - end - end - end - - private - - def define_reader(name, locale) - warning_message = "locale passed as option to locale accessor will be ignored".freeze - normalized_locale = Mobility.normalize_locale(locale) - - define_method "#{name}_#{normalized_locale}" do |**options| - return super() if options.delete(:super) - warn warning_message if options.delete(:locale) - Mobility.with_locale(locale) { send(name, options) } - end - - define_method "#{name}_#{normalized_locale}?" do |**options| - return super() if options.delete(:super) - warn warning_message if options.delete(:locale) - Mobility.with_locale(locale) { send("#{name}?", options) } - end - end - - def define_writer(name, locale) - warning_message = "locale passed as option to locale accessor will be ignored".freeze - normalized_locale = Mobility.normalize_locale(locale) - - define_method "#{name}_#{normalized_locale}=" do |value, **options| - return super(value) if options.delete(:super) - warn warning_message if options.delete(:locale) - Mobility.with_locale(locale) { send("#{name}=", value, options) } - end - end - end -end diff --git a/lib/mobility/plugins.rb b/lib/mobility/plugins.rb new file mode 100644 index 000000000..129f10dc9 --- /dev/null +++ b/lib/mobility/plugins.rb @@ -0,0 +1,45 @@ +module Mobility +=begin + +Plugins allow modular customization of backends independent of the backend +itself. They are enabled through the {Configuration.plugins} configuration +setting, which takes an array of symbols corresponding to plugin names. The +order of these names is important since it determines the order in which +plugins will be applied. + +So if our {Configuration.plugins} is an array +[:foo]+, and we call +`translates` on our model, +Post+, like this: + + class Post + translates :title, foo: true + end + +Then the +Foo+ plugin will be applied with the option value +true+. Applying a +module calls a class method, +apply+ (in this case +Foo.apply+), which takes +two arguments: + +- an instance of the {Attributes} class, +attributes+, from which the backend + can configure the backend class (+attributes.backend_class+) and the model + (+attributes.model_class+), and the +attributes+ module itself (which + will be included into the backend). +- the value of the +option+ passed into the model with +translates+ (in this + case, +true+). + +Typically, the plugin will include a module into either ++attributes.backend_class+ or +attributes+ itself, configured according to the +option value. For examples, see classes under the {Mobility::Plugins} namespace. + +=end + module Plugins + autoload :ActiveModel, 'mobility/plugins/active_model' + autoload :ActiveRecord, 'mobility/plugins/active_record' + autoload :Cache, 'mobility/plugins/cache' + autoload :Default, 'mobility/plugins/default' + autoload :Dirty, 'mobility/plugins/dirty' + autoload :Fallbacks, 'mobility/plugins/fallbacks' + autoload :FallthroughAccessors, 'mobility/plugins/fallthrough_accessors' + autoload :LocaleAccessors, 'mobility/plugins/locale_accessors' + autoload :Presence, 'mobility/plugins/presence' + autoload :Sequel, 'mobility/plugins/sequel' + end +end diff --git a/lib/mobility/plugins/active_model.rb b/lib/mobility/plugins/active_model.rb new file mode 100644 index 000000000..2060be716 --- /dev/null +++ b/lib/mobility/plugins/active_model.rb @@ -0,0 +1,7 @@ +module Mobility + module Plugins + module ActiveModel + autoload :Dirty, 'mobility/plugins/active_model/dirty' + end + end +end diff --git a/lib/mobility/backend/active_model/dirty.rb b/lib/mobility/plugins/active_model/dirty.rb similarity index 99% rename from lib/mobility/backend/active_model/dirty.rb rename to lib/mobility/plugins/active_model/dirty.rb index d0995bea4..9b0d7e374 100644 --- a/lib/mobility/backend/active_model/dirty.rb +++ b/lib/mobility/plugins/active_model/dirty.rb @@ -1,7 +1,7 @@ # frozen-string-literal: true module Mobility - module Backend + module Plugins =begin Dirty tracking for models which include the +ActiveModel::Dirty+ module. diff --git a/lib/mobility/plugins/active_record.rb b/lib/mobility/plugins/active_record.rb new file mode 100644 index 000000000..d2ff5a0d3 --- /dev/null +++ b/lib/mobility/plugins/active_record.rb @@ -0,0 +1,7 @@ +module Mobility + module Plugins + module ActiveRecord + autoload :Dirty, 'mobility/plugins/active_record/dirty' + end + end +end diff --git a/lib/mobility/backend/active_record/dirty.rb b/lib/mobility/plugins/active_record/dirty.rb similarity index 96% rename from lib/mobility/backend/active_record/dirty.rb rename to lib/mobility/plugins/active_record/dirty.rb index f126468b6..53a46aa0d 100644 --- a/lib/mobility/backend/active_record/dirty.rb +++ b/lib/mobility/plugins/active_record/dirty.rb @@ -1,10 +1,10 @@ # frozen-string-literal: true module Mobility - module Backend + module Plugins =begin -Dirty tracking for AR models. See {Mobility::Backend::ActiveModel::Dirty} for +Dirty tracking for AR models. See {Mobility::Plugins::ActiveModel::Dirty} for details on usage. =end diff --git a/lib/mobility/backend/cache.rb b/lib/mobility/plugins/cache.rb similarity index 88% rename from lib/mobility/backend/cache.rb rename to lib/mobility/plugins/cache.rb index 45b1acfb5..fdf9a07fa 100644 --- a/lib/mobility/backend/cache.rb +++ b/lib/mobility/plugins/cache.rb @@ -1,11 +1,13 @@ +require "mobility/plugins/cache/translation_cacher" + module Mobility - module Backend + module Plugins =begin Caches values fetched from the backend so subsequent fetches can be performed more quickly. The cache stores cached values in a simple hash, which is not optimal for some storage strategies, so some backends (KeyValue, Table) use a -custom module through the {Mobility::Backend::Setup#apply_module} hook. For +custom module through the {Mobility::Backend::Setup#apply_plugin} hook. For details see the documentation for these backends. The cache is reset when one of a set of events happens (saving, reloading, @@ -18,13 +20,13 @@ module Backend =end module Cache - # Applies cache option module to attributes. + # Applies cache plugin to attributes. # @param [Attributes] attributes # @param [Boolean] option def self.apply(attributes, option) if option backend_class = attributes.backend_class - backend_class.include(self) unless backend_class.apply_module(:cache) + backend_class.include(self) unless backend_class.apply_plugin(:cache) model_class = attributes.model_class model_class.include BackendResetter.for(model_class).new(attributes.names) { clear_cache } diff --git a/lib/mobility/plugins/cache/translation_cacher.rb b/lib/mobility/plugins/cache/translation_cacher.rb new file mode 100644 index 000000000..db1b6dae4 --- /dev/null +++ b/lib/mobility/plugins/cache/translation_cacher.rb @@ -0,0 +1,40 @@ +module Mobility + module Plugins + module Cache +=begin + +Creates a module to cache a given translation fetch method. The cacher defines +private methods +cache+ and +clear_cache+ to access and clear, respectively, a +translations hash. + +This cacher is used to cache translation values in {Mobility::Plugins::Cache}, +and also to cache translation *records* in {Mobility::Backends::Table} and +{Mobility::Backends::KeyValue}. + +=end + class TranslationCacher < Module + # @param [Symbol] fetch_method Name of translation fetch method to cache + def initialize(fetch_method) + define_method fetch_method do |locale, **options| + return super(locale, options) if options.delete(:cache) == false + if cache.has_key?(locale) + cache[locale] + else + cache[locale] = super(locale, options) + end + end + + define_method :cache do + @cache ||= {} + end + + define_method :clear_cache do + @cache = {} + end + + private :cache, :clear_cache + end + end + end + end +end diff --git a/lib/mobility/backend/default.rb b/lib/mobility/plugins/default.rb similarity index 95% rename from lib/mobility/backend/default.rb rename to lib/mobility/plugins/default.rb index ceaa93d73..1c91f8f92 100644 --- a/lib/mobility/backend/default.rb +++ b/lib/mobility/plugins/default.rb @@ -1,5 +1,5 @@ module Mobility - module Backend + module Plugins =begin Defines value or proc to fall through to if return value from getter would @@ -51,7 +51,7 @@ class Post #=> "Post" =end class Default < Module - # Applies default option module to attributes. + # Applies default plugin to attributes. # @param [Attributes] attributes # @param [Object] option def self.apply(attributes, option) diff --git a/lib/mobility/backend/dirty.rb b/lib/mobility/plugins/dirty.rb similarity index 86% rename from lib/mobility/backend/dirty.rb rename to lib/mobility/plugins/dirty.rb index c8ea7abc2..3fcad4ec8 100644 --- a/lib/mobility/backend/dirty.rb +++ b/lib/mobility/plugins/dirty.rb @@ -1,12 +1,12 @@ module Mobility - module Backend + module Plugins =begin Dirty tracking for Mobility attributes. See class-specific implementations for details. -@see Mobility::Backend::ActiveModel::Dirty -@see Mobility::Backend::Sequel::Dirty +@see Mobility::Plugins::ActiveModel::Dirty +@see Mobility::Plugins::Sequel::Dirty @note Dirty tracking can have unexpected results when combined with fallbacks. A change in the fallback locale value will not mark an attribute falling @@ -20,7 +20,7 @@ module Backend =end module Dirty class << self - # Applies dirty option module to attributes for a given option value. + # Applies dirty plugin to attributes for a given option value. # @param [Attributes] attributes # @param [Boolean] option Value of option # @raise [ArgumentError] if model class does not support dirty tracking @@ -37,9 +37,9 @@ def include_dirty_module(backend_class, model_class, *attribute_names) dirty_module = if Loaded::ActiveRecord && model_class.ancestors.include?(::ActiveModel::Dirty) (model_class < ::ActiveRecord::Base) ? - Backend::ActiveRecord::Dirty : Backend::ActiveModel::Dirty + Plugins::ActiveRecord::Dirty : Plugins::ActiveModel::Dirty elsif Loaded::Sequel && model_class < ::Sequel::Model - Backend::Sequel::Dirty + Plugins::Sequel::Dirty else raise ArgumentError, "#{model_class} does not support Dirty module." end diff --git a/lib/mobility/backend/fallbacks.rb b/lib/mobility/plugins/fallbacks.rb similarity index 97% rename from lib/mobility/backend/fallbacks.rb rename to lib/mobility/plugins/fallbacks.rb index 10e3bd1fe..ee94b1a31 100644 --- a/lib/mobility/backend/fallbacks.rb +++ b/lib/mobility/plugins/fallbacks.rb @@ -1,5 +1,5 @@ module Mobility - module Backend + module Plugins =begin Falls back to one or more alternative locales in case no value is defined for a @@ -76,7 +76,7 @@ class Post #=> "Mobilité" =end class Fallbacks < Module - # Applies fallbacks option module to attributes. + # Applies fallbacks plugin to attributes. # @param [Attributes] attributes # @param [Boolean] option def self.apply(attributes, option) diff --git a/lib/mobility/plugins/fallthrough_accessors.rb b/lib/mobility/plugins/fallthrough_accessors.rb new file mode 100644 index 000000000..4f53c8596 --- /dev/null +++ b/lib/mobility/plugins/fallthrough_accessors.rb @@ -0,0 +1,66 @@ +# frozen-string-literal: true + +module Mobility + module Plugins +=begin + +Defines +method_missing+ and +respond_to_missing?+ methods for a set of +attributes such that a method call using a locale accessor, like: + + article.title_pt_br + +will return the value of +article.title+ with the locale set to +pt-BR+ around +the method call. The class is called "FallthroughAccessors" because when +included in a model class, locale-specific methods will be available even if +not explicitly defined with the +locale_accessors+ option. + +This is a less efficient (but more open-ended) implementation of locale +accessors, for use in cases where the locales to be used are not known when the +model class is generated. + +@example Using fallthrough locales on a plain old ruby class + class Post + def title + "title in #{Mobility.locale}" + end + include Mobility::FallthroughAccessors.new("title") + end + + Mobility.locale = :en + post = Post.new + post.title + #=> "title in en" + post.title_fr + #=> "title in fr" + +=end + class FallthroughAccessors < Module + # Apply fallthrough accessors plugin to attributes. + # @param [Attributes] attributes + # @param [Boolean] option + def self.apply(attributes, option) + attributes.model_class.include new(*attributes.names) if option + end + + # @param [String] One or more attributes + def initialize(*attributes) + method_name_regex = /\A(#{attributes.join('|'.freeze)})_([a-z]{2}(_[a-z]{2})?)(=?|\??)\z/.freeze + + define_method :method_missing do |method_name, *arguments, &block| + if method_name =~ method_name_regex + attribute = $1.to_sym + locale, suffix = $2.split('_'.freeze) + locale = "#{locale}-#{suffix.upcase}".freeze if suffix + Mobility.with_locale(locale) { public_send("#{attribute}#{$4}".freeze, *arguments) } + else + super(method_name, *arguments, &block) + end + end + + define_method :respond_to_missing? do |method_name, include_private = false| + (method_name =~ method_name_regex) || super(method_name, include_private) + end + end + end + end +end diff --git a/lib/mobility/plugins/locale_accessors.rb b/lib/mobility/plugins/locale_accessors.rb new file mode 100644 index 000000000..03bd34449 --- /dev/null +++ b/lib/mobility/plugins/locale_accessors.rb @@ -0,0 +1,84 @@ +# frozen-string-literal: true + +module Mobility + module Plugins +=begin + +Defines methods for a set of locales to access translated attributes in those +locales directly with a method call, using a suffix including the locale: + + article.title_pt_br + +If no locales are passed as an option to the initializer, ++I18n.available_locales+ will be used by default. + +@example + class Post + def title + "title in #{Mobility.locale}" + end + include Mobility::Plugins::LocaleAccessors.new("title", locales: [:en, :fr]) + end + + Mobility.locale = :en + post = Post.new + post.title + #=> "title in en" + post.title_fr + #=> "title in fr" + +=end + class LocaleAccessors < Module + # Apply locale accessors plugin to attributes. + # @param [Attributes] attributes + # @param [Boolean] option + def self.apply(attributes, option) + if accessor_locales = option + accessor_locales = Mobility.config.default_accessor_locales if accessor_locales == true + attributes.model_class.include new(*attributes.names, locales: accessor_locales) + end + end + + # @param [String] One or more attribute names + # @param [Array] Locales + def initialize(*attribute_names, locales: I18n.available_locales) + attribute_names.each do |name| + locales.each do |locale| + define_reader(name, locale) + define_writer(name, locale) + end + end + end + + private + + def define_reader(name, locale) + warning_message = "locale passed as option to locale accessor will be ignored".freeze + normalized_locale = Mobility.normalize_locale(locale) + + define_method "#{name}_#{normalized_locale}" do |**options| + return super() if options.delete(:super) + warn warning_message if options.delete(:locale) + Mobility.with_locale(locale) { send(name, options) } + end + + define_method "#{name}_#{normalized_locale}?" do |**options| + return super() if options.delete(:super) + warn warning_message if options.delete(:locale) + Mobility.with_locale(locale) { send("#{name}?", options) } + end + end + + def define_writer(name, locale) + warning_message = "locale passed as option to locale accessor will be ignored".freeze + normalized_locale = Mobility.normalize_locale(locale) + + define_method "#{name}_#{normalized_locale}=" do |value, **options| + return super(value) if options.delete(:super) + warn warning_message if options.delete(:locale) + Mobility.with_locale(locale) { send("#{name}=", value, options) } + end + end + end + end +end diff --git a/lib/mobility/backend/presence.rb b/lib/mobility/plugins/presence.rb similarity index 93% rename from lib/mobility/backend/presence.rb rename to lib/mobility/plugins/presence.rb index 0dd182daa..9b4514aed 100644 --- a/lib/mobility/backend/presence.rb +++ b/lib/mobility/plugins/presence.rb @@ -1,5 +1,5 @@ module Mobility - module Backend + module Plugins =begin Applies presence filter to values fetched from backend and to values set on @@ -7,7 +7,7 @@ module Backend =end module Presence - # Applies presence option module to attributes. + # Applies presence plugin to attributes. # @param [Attributes] attributes # @param [Boolean] option def self.apply(attributes, option) diff --git a/lib/mobility/plugins/sequel.rb b/lib/mobility/plugins/sequel.rb new file mode 100644 index 000000000..0e9255508 --- /dev/null +++ b/lib/mobility/plugins/sequel.rb @@ -0,0 +1,7 @@ +module Mobility + module Plugins + module Sequel + autoload :Dirty, 'mobility/plugins/sequel/dirty' + end + end +end diff --git a/lib/mobility/backend/sequel/dirty.rb b/lib/mobility/plugins/sequel/dirty.rb similarity index 99% rename from lib/mobility/backend/sequel/dirty.rb rename to lib/mobility/plugins/sequel/dirty.rb index 2792c671d..d40b0e309 100644 --- a/lib/mobility/backend/sequel/dirty.rb +++ b/lib/mobility/plugins/sequel/dirty.rb @@ -2,7 +2,7 @@ require "sequel/plugins/dirty" module Mobility - module Backend + module Plugins =begin Dirty tracking for Sequel models which use the +Sequel::Plugins::Dirty+ plugin. diff --git a/lib/mobility/sequel/model_translation.rb b/lib/mobility/sequel/model_translation.rb index 6bd9070ed..54f1c5d3b 100644 --- a/lib/mobility/sequel/model_translation.rb +++ b/lib/mobility/sequel/model_translation.rb @@ -3,7 +3,7 @@ module Sequel =begin Module included in translation class dynamically generated by -{Backend::Sequel::Table} backend. +{Backends::Sequel::Table} backend. =end module ModelTranslation diff --git a/lib/rails/generators/mobility/translations_generator.rb b/lib/rails/generators/mobility/translations_generator.rb index baed479fd..7ae1f7c60 100644 --- a/lib/rails/generators/mobility/translations_generator.rb +++ b/lib/rails/generators/mobility/translations_generator.rb @@ -52,7 +52,7 @@ def self.prepare_for_invocation(name, value) if SUPPORTED_BACKENDS.include?(value) require_relative "./backend_generators/#{value}_backend".freeze Mobility::BackendGenerators.const_get("#{value}_backend".camelcase.freeze) - elsif Mobility::Backend.const_get(value.to_s.camelize.gsub(/\s+/, ''.freeze)) + elsif Mobility::Backends.const_get(value.to_s.camelize.gsub(/\s+/, ''.freeze)) raise Thor::Error, "The #{value} backend does not have a translations generator." else raise Thor::Error, "#{value} is not a Mobility backend." diff --git a/spec/mobility/attributes_spec.rb b/spec/mobility/attributes_spec.rb index 6c51073ec..160fb8c8c 100644 --- a/spec/mobility/attributes_spec.rb +++ b/spec/mobility/attributes_spec.rb @@ -13,7 +13,7 @@ let(:backend) { double("backend") } let(:backend_class) do backend_double = backend - Class.new(Mobility::Backend::Null) do + Class.new(Mobility::Backends::Null) do define_method :read do |*args| backend_double.read(*args) end @@ -66,17 +66,17 @@ end describe "cache" do - it "includes Backend::Cache into backend when options[:cache] is not false" do + it "includes Plugins::Cache into backend when options[:cache] is not false" do clean_options.delete(:cache) attributes = described_class.new(:accessor, "title", backend: backend_class, **clean_options) Article.include attributes - expect(attributes.backend_class.ancestors).to include(Mobility::Backend::Cache) + expect(attributes.backend_class.ancestors).to include(Mobility::Plugins::Cache) end - it "does not include Backend::Cache into backend when options[:cache] is false" do + it "does not include Plugins::Cache into backend when options[:cache] is false" do attributes = described_class.new(:accessor, "title", backend: backend_class, **clean_options) Article.include attributes - expect(attributes.backend_class.ancestors).not_to include(Mobility::Backend::Cache) + expect(attributes.backend_class.ancestors).not_to include(Mobility::Plugins::Cache) end end @@ -89,7 +89,7 @@ it "defines _backend method which returns backend instance" do expect(backend_class).to receive(:new).once.with(article, "title", expected_options).and_call_original - expect(article.mobility_backend_for("title")).to be_a(Mobility::Backend::Null) + expect(article.mobility_backend_for("title")).to be_a(Mobility::Backends::Null) end it "memoizes backend instance" do diff --git a/spec/mobility/backend/active_record/column_spec.rb b/spec/mobility/backends/active_record/column_spec.rb similarity index 95% rename from spec/mobility/backend/active_record/column_spec.rb rename to spec/mobility/backends/active_record/column_spec.rb index 268a3bcec..4be8a95dd 100644 --- a/spec/mobility/backend/active_record/column_spec.rb +++ b/spec/mobility/backends/active_record/column_spec.rb @@ -1,9 +1,9 @@ require "spec_helper" -describe Mobility::Backend::ActiveRecord::Column, orm: :active_record do +describe Mobility::Backends::ActiveRecord::Column, orm: :active_record do extend Helpers::ActiveRecord - context "with no option modules applied" do + context "with no plugins applied" do model_class = Class.new(ActiveRecord::Base) do include Mobility self.table_name = 'comments' @@ -11,7 +11,7 @@ include_backend_examples described_class, model_class, "content" end - context "with standard option modules applied" do + context "with standard plugins applied" do let(:attributes) { %w[content author] } let(:options) { {} } let(:backend) { described_class.new(comment, attributes.first, options) } diff --git a/spec/mobility/backend/active_record/hstore_spec.rb b/spec/mobility/backends/active_record/hstore_spec.rb similarity index 85% rename from spec/mobility/backend/active_record/hstore_spec.rb rename to spec/mobility/backends/active_record/hstore_spec.rb index fbaa8af09..51329a287 100644 --- a/spec/mobility/backend/active_record/hstore_spec.rb +++ b/spec/mobility/backends/active_record/hstore_spec.rb @@ -1,16 +1,16 @@ require "spec_helper" -describe Mobility::Backend::ActiveRecord::Hstore, orm: :active_record, db: :postgres do +describe Mobility::Backends::ActiveRecord::Hstore, orm: :active_record, db: :postgres do extend Helpers::ActiveRecord - context "with no option modules applied" do + context "with no plugins applied" do include_backend_examples described_class, (Class.new(ActiveRecord::Base) do include Mobility self.table_name = 'hstore_posts' end) end - context "with standard option modules applied" do + context "with standard plugins applied" do let(:backend) { post.mobility_backend_for("title") } before do diff --git a/spec/mobility/backend/active_record/jsonb_spec.rb b/spec/mobility/backends/active_record/jsonb_spec.rb similarity index 87% rename from spec/mobility/backend/active_record/jsonb_spec.rb rename to spec/mobility/backends/active_record/jsonb_spec.rb index f2edf225a..cdb135ba0 100644 --- a/spec/mobility/backend/active_record/jsonb_spec.rb +++ b/spec/mobility/backends/active_record/jsonb_spec.rb @@ -1,16 +1,16 @@ require "spec_helper" -describe Mobility::Backend::ActiveRecord::Jsonb, orm: :active_record, db: :postgres do +describe Mobility::Backends::ActiveRecord::Jsonb, orm: :active_record, db: :postgres do extend Helpers::ActiveRecord - context "with no option modules applied" do + context "with no plugins applied" do include_backend_examples described_class, (Class.new(ActiveRecord::Base) do include Mobility self.table_name = 'jsonb_posts' end) end - context "with standard option modules applied" do + context "with standard plugins applied" do let(:backend) { post.mobility_backend_for("title") } before do diff --git a/spec/mobility/backend/active_record/key_value_spec.rb b/spec/mobility/backends/active_record/key_value_spec.rb similarity index 99% rename from spec/mobility/backend/active_record/key_value_spec.rb rename to spec/mobility/backends/active_record/key_value_spec.rb index b5b17d0cc..5dfce4659 100644 --- a/spec/mobility/backend/active_record/key_value_spec.rb +++ b/spec/mobility/backends/active_record/key_value_spec.rb @@ -1,9 +1,9 @@ require "spec_helper" -describe Mobility::Backend::ActiveRecord::KeyValue, orm: :active_record do +describe Mobility::Backends::ActiveRecord::KeyValue, orm: :active_record do extend Helpers::ActiveRecord - context "with no option modules applied" do + context "with no plugins applied" do before do stub_const 'Article', Class.new(ActiveRecord::Base) Article.include Mobility @@ -12,7 +12,7 @@ include_backend_examples described_class, 'Article' end - context "with standard option modules applied" do + context "with standard plugins applied" do let(:title_backend) { article.mobility_backend_for("title") } let(:content_backend) { article.mobility_backend_for("content") } let(:cache) { false } diff --git a/spec/mobility/backend/active_record/serialized_spec.rb b/spec/mobility/backends/active_record/serialized_spec.rb similarity index 97% rename from spec/mobility/backend/active_record/serialized_spec.rb rename to spec/mobility/backends/active_record/serialized_spec.rb index f9e705b8b..461b9ee2e 100644 --- a/spec/mobility/backend/active_record/serialized_spec.rb +++ b/spec/mobility/backends/active_record/serialized_spec.rb @@ -1,16 +1,16 @@ require "spec_helper" -describe Mobility::Backend::ActiveRecord::Serialized, orm: :active_record do +describe Mobility::Backends::ActiveRecord::Serialized, orm: :active_record do extend Helpers::ActiveRecord - context "with no option modules applied" do + context "with no plugins applied" do include_backend_examples described_class, (Class.new(ActiveRecord::Base) do include Mobility self.table_name = 'serialized_posts' end) end - context "with standard option modules applied" do + context "with standard plugins applied" do before do stub_const 'SerializedPost', Class.new(ActiveRecord::Base) SerializedPost.include Mobility diff --git a/spec/mobility/backend/active_record/table_spec.rb b/spec/mobility/backends/active_record/table_spec.rb similarity index 98% rename from spec/mobility/backend/active_record/table_spec.rb rename to spec/mobility/backends/active_record/table_spec.rb index 632fcd4f1..fa01e2009 100644 --- a/spec/mobility/backend/active_record/table_spec.rb +++ b/spec/mobility/backends/active_record/table_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe Mobility::Backend::ActiveRecord::Table, orm: :active_record do +describe Mobility::Backends::ActiveRecord::Table, orm: :active_record do extend Helpers::ActiveRecord before do @@ -8,7 +8,7 @@ Article.include Mobility end - context "with no option modules applied" do + context "with no plugins applied" do include_backend_examples described_class, 'Article' end diff --git a/spec/mobility/backend/active_record_spec.rb b/spec/mobility/backends/active_record_spec.rb similarity index 96% rename from spec/mobility/backend/active_record_spec.rb rename to spec/mobility/backends/active_record_spec.rb index 14afeaa27..632dcba38 100644 --- a/spec/mobility/backend/active_record_spec.rb +++ b/spec/mobility/backends/active_record_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe Mobility::Backend::ActiveRecord, orm: :active_record do +describe Mobility::Backends::ActiveRecord, orm: :active_record do context "model with multiple backends" do before do stub_const 'Comment', Class.new(ActiveRecord::Base) diff --git a/spec/mobility/backend/sequel/column_spec.rb b/spec/mobility/backends/sequel/column_spec.rb similarity index 95% rename from spec/mobility/backend/sequel/column_spec.rb rename to spec/mobility/backends/sequel/column_spec.rb index d23118626..f8ff7ca14 100644 --- a/spec/mobility/backend/sequel/column_spec.rb +++ b/spec/mobility/backends/sequel/column_spec.rb @@ -1,9 +1,9 @@ require "spec_helper" -describe Mobility::Backend::Sequel::Column, orm: :sequel do +describe Mobility::Backends::Sequel::Column, orm: :sequel do extend Helpers::Sequel - context "with no option modules applied" do + context "with no plugins applied" do model_class = Class.new(Sequel::Model(:comments)) do include Mobility end @@ -11,7 +11,7 @@ include_backend_examples described_class, model_class, :content end - context "with standard option modules applied" do + context "with standard plugins applied" do let(:attributes) { %w[content author] } let(:options) { {} } let(:backend) { described_class.new(comment, attributes.first, options) } diff --git a/spec/mobility/backend/sequel/hstore_spec.rb b/spec/mobility/backends/sequel/hstore_spec.rb similarity index 85% rename from spec/mobility/backend/sequel/hstore_spec.rb rename to spec/mobility/backends/sequel/hstore_spec.rb index 3dde371d1..e5ab679fb 100644 --- a/spec/mobility/backend/sequel/hstore_spec.rb +++ b/spec/mobility/backends/sequel/hstore_spec.rb @@ -1,15 +1,15 @@ require "spec_helper" -describe Mobility::Backend::Sequel::Hstore, orm: :sequel, db: :postgres do +describe Mobility::Backends::Sequel::Hstore, orm: :sequel, db: :postgres do extend Helpers::Sequel - context "with no option modules applied" do + context "with no plugins applied" do include_backend_examples described_class, (Class.new(Sequel::Model(:hstore_posts)) do include Mobility end) end - context "with standard option modules applied" do + context "with standard plugins applied" do let(:backend) { post.mobility_backend_for("title") } before do diff --git a/spec/mobility/backend/sequel/jsonb_spec.rb b/spec/mobility/backends/sequel/jsonb_spec.rb similarity index 87% rename from spec/mobility/backend/sequel/jsonb_spec.rb rename to spec/mobility/backends/sequel/jsonb_spec.rb index 161374bc1..72cce73f3 100644 --- a/spec/mobility/backend/sequel/jsonb_spec.rb +++ b/spec/mobility/backends/sequel/jsonb_spec.rb @@ -1,15 +1,15 @@ require "spec_helper" -describe Mobility::Backend::Sequel::Jsonb, orm: :sequel, db: :postgres do +describe Mobility::Backends::Sequel::Jsonb, orm: :sequel, db: :postgres do extend Helpers::Sequel - context "with no option modules applied" do + context "with no plugins applied" do include_backend_examples described_class, (Class.new(Sequel::Model(:jsonb_posts)) do include Mobility end) end - context "with standard option modules applied" do + context "with standard plugins applied" do let(:backend) { post.mobility_backend_for("title") } before do diff --git a/spec/mobility/backend/sequel/key_value_spec.rb b/spec/mobility/backends/sequel/key_value_spec.rb similarity index 98% rename from spec/mobility/backend/sequel/key_value_spec.rb rename to spec/mobility/backends/sequel/key_value_spec.rb index a13dea03e..d3cbbdfb6 100644 --- a/spec/mobility/backend/sequel/key_value_spec.rb +++ b/spec/mobility/backends/sequel/key_value_spec.rb @@ -1,23 +1,23 @@ require "spec_helper" -describe Mobility::Backend::Sequel::KeyValue, orm: :sequel do +describe Mobility::Backends::Sequel::KeyValue, orm: :sequel do extend Helpers::Sequel # Note: the cache is required for the Sequel Table backend, so we need to # apply it. - context "with only cache option module applied" do + context "with only cache plugins applied" do before do stub_const 'Article', Class.new(Sequel::Model(:articles)) Article.include Mobility end backend_class_with_cache = Class.new(described_class) - backend_class_with_cache.include(Mobility::Backend::Table::Cache) + backend_class_with_cache.include(Mobility::Backends::Table::Cache) include_backend_examples backend_class_with_cache, 'Article' end - context "with standard option modules applied" do - let(:described_class) { Mobility::Backend::Sequel::KeyValue } + context "with standard plugins applied" do + let(:described_class) { Mobility::Backends::Sequel::KeyValue } let(:translation_class) { Mobility::Sequel::TextTranslation } let(:title_backend) { article.mobility_backend_for("title") } let(:content_backend) { article.mobility_backend_for("content") } diff --git a/spec/mobility/backend/sequel/serialized_spec.rb b/spec/mobility/backends/sequel/serialized_spec.rb similarity index 98% rename from spec/mobility/backend/sequel/serialized_spec.rb rename to spec/mobility/backends/sequel/serialized_spec.rb index 4ec0cf0d4..b7daef546 100644 --- a/spec/mobility/backend/sequel/serialized_spec.rb +++ b/spec/mobility/backends/sequel/serialized_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe Mobility::Backend::Sequel::Serialized, orm: :sequel do +describe Mobility::Backends::Sequel::Serialized, orm: :sequel do extend Helpers::Sequel context "with no options applied" do diff --git a/spec/mobility/backend/sequel/table_spec.rb b/spec/mobility/backends/sequel/table_spec.rb similarity index 96% rename from spec/mobility/backend/sequel/table_spec.rb rename to spec/mobility/backends/sequel/table_spec.rb index f484216ce..4cd4843fb 100644 --- a/spec/mobility/backend/sequel/table_spec.rb +++ b/spec/mobility/backends/sequel/table_spec.rb @@ -1,17 +1,17 @@ require "spec_helper" -describe Mobility::Backend::Sequel::Table, orm: :sequel do +describe Mobility::Backends::Sequel::Table, orm: :sequel do extend Helpers::Sequel # Note: the cache is required for the Sequel Table backend, so we need to # apply it. - context "with only cache option module applied" do + context "with only cache plugins applied" do before do stub_const 'Article', Class.new(Sequel::Model(:articles)) Article.include Mobility end backend_class_with_cache = Class.new(described_class) - backend_class_with_cache.include(Mobility::Backend::KeyValue::Cache) + backend_class_with_cache.include(Mobility::Backends::KeyValue::Cache) include_backend_examples backend_class_with_cache, 'Article' end diff --git a/spec/mobility/backend/sequel_spec.rb b/spec/mobility/backends/sequel_spec.rb similarity index 96% rename from spec/mobility/backend/sequel_spec.rb rename to spec/mobility/backends/sequel_spec.rb index 0905e683a..820e3dc65 100644 --- a/spec/mobility/backend/sequel_spec.rb +++ b/spec/mobility/backends/sequel_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe Mobility::Backend::Sequel, orm: :sequel do +describe Mobility::Backends::Sequel, orm: :sequel do context "model with multiple backends" do before do stub_const 'Comment', Class.new(Sequel::Model) diff --git a/spec/mobility/backend/active_model/dirty_spec.rb b/spec/mobility/plugins/active_model/dirty_spec.rb similarity index 98% rename from spec/mobility/backend/active_model/dirty_spec.rb rename to spec/mobility/plugins/active_model/dirty_spec.rb index e2694f033..7d7f55aaa 100644 --- a/spec/mobility/backend/active_model/dirty_spec.rb +++ b/spec/mobility/plugins/active_model/dirty_spec.rb @@ -1,8 +1,8 @@ require "spec_helper" -describe Mobility::Backend::ActiveModel::Dirty, orm: :active_record do +describe Mobility::Plugins::ActiveModel::Dirty, orm: :active_record do let(:backend_class) do - Class.new(Mobility::Backend::Null) do + Class.new(Mobility::Backends::Null) do def read(locale, **options) values[locale] end diff --git a/spec/mobility/backend/active_record/dirty_spec.rb b/spec/mobility/plugins/active_record/dirty_spec.rb similarity index 98% rename from spec/mobility/backend/active_record/dirty_spec.rb rename to spec/mobility/plugins/active_record/dirty_spec.rb index 379200176..64b7da4bc 100644 --- a/spec/mobility/backend/active_record/dirty_spec.rb +++ b/spec/mobility/plugins/active_record/dirty_spec.rb @@ -1,8 +1,8 @@ require "spec_helper" -describe Mobility::Backend::ActiveRecord::Dirty, orm: :active_record do +describe Mobility::Plugins::ActiveRecord::Dirty, orm: :active_record do let(:backend_class) do - Class.new(Mobility::Backend::Null) do + Class.new(Mobility::Backends::Null) do def read(locale, **options) values[locale] end diff --git a/spec/mobility/backend/cache_spec.rb b/spec/mobility/plugins/cache_spec.rb similarity index 99% rename from spec/mobility/backend/cache_spec.rb rename to spec/mobility/plugins/cache_spec.rb index 3f2830aff..a50fe5438 100644 --- a/spec/mobility/backend/cache_spec.rb +++ b/spec/mobility/plugins/cache_spec.rb @@ -1,9 +1,9 @@ require "spec_helper" -describe Mobility::Backend::Cache do +describe Mobility::Plugins::Cache do describe "when included into a class" do let(:backend_class) do - Class.new(Mobility::Backend::Null) do + Class.new(Mobility::Backends::Null) do def read(*args) spy.read(*args) end diff --git a/spec/mobility/backend/default_spec.rb b/spec/mobility/plugins/default_spec.rb similarity index 96% rename from spec/mobility/backend/default_spec.rb rename to spec/mobility/plugins/default_spec.rb index 7d6abd4f6..93242ed9b 100644 --- a/spec/mobility/backend/default_spec.rb +++ b/spec/mobility/plugins/default_spec.rb @@ -1,13 +1,13 @@ require "spec_helper" -describe Mobility::Backend::Default do +describe Mobility::Plugins::Default do describe "when included into a class" do let(:default) { 'default foo' } let(:backend_double) { double("backend") } let(:backend) { backend_class.new("model", "title", default: default) } let(:backend_class) do backend_double_ = backend_double - backend_class = Class.new(Mobility::Backend::Null) do + backend_class = Class.new(Mobility::Backends::Null) do define_method :read do |*args| backend_double_.read(*args) end diff --git a/spec/mobility/backend/dirty_spec.rb b/spec/mobility/plugins/dirty_spec.rb similarity index 75% rename from spec/mobility/backend/dirty_spec.rb rename to spec/mobility/plugins/dirty_spec.rb index e7c92fe55..75975d606 100644 --- a/spec/mobility/backend/dirty_spec.rb +++ b/spec/mobility/plugins/dirty_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe Mobility::Backend::Dirty do +describe Mobility::Plugins::Dirty do describe ".apply" do context "option value is truthy" do let(:attributes) do @@ -8,7 +8,7 @@ end let(:backend_class) { Class.new } before do - expect(Mobility::FallthroughAccessors).to receive(:apply).with(attributes, true) + expect(Mobility::Plugins::FallthroughAccessors).to receive(:apply).with(attributes, true) end context "model_class includes ActiveModel::Dirty", orm: :active_record do @@ -16,9 +16,9 @@ let(:model_class) { Class.new(ActiveRecord::Base) } it "includes dirty modules into backend class and model class" do - expect(backend_class).to receive(:include).with(Mobility::Backend::ActiveRecord::Dirty) - methods = instance_double(Mobility::Backend::ActiveRecord::Dirty::MethodsBuilder) - expect(Mobility::Backend::ActiveRecord::Dirty::MethodsBuilder).to receive(:new).with("title").and_return(methods) + expect(backend_class).to receive(:include).with(Mobility::Plugins::ActiveRecord::Dirty) + methods = instance_double(Mobility::Plugins::ActiveRecord::Dirty::MethodsBuilder) + expect(Mobility::Plugins::ActiveRecord::Dirty::MethodsBuilder).to receive(:new).with("title").and_return(methods) expect(model_class).to receive(:include).with(methods) described_class.apply(attributes, true) end @@ -32,9 +32,9 @@ end it "includes dirty modules into backend class and model class" do - expect(backend_class).to receive(:include).with(Mobility::Backend::ActiveModel::Dirty) - methods = instance_double(Mobility::Backend::ActiveModel::Dirty::MethodsBuilder) - expect(Mobility::Backend::ActiveModel::Dirty::MethodsBuilder).to receive(:new).with("title").and_return(methods) + expect(backend_class).to receive(:include).with(Mobility::Plugins::ActiveModel::Dirty) + methods = instance_double(Mobility::Plugins::ActiveModel::Dirty::MethodsBuilder) + expect(Mobility::Plugins::ActiveModel::Dirty::MethodsBuilder).to receive(:new).with("title").and_return(methods) expect(model_class).to receive(:include).with(methods) described_class.apply(attributes, true) end @@ -45,9 +45,9 @@ let(:model_class) { Class.new(Sequel::Model) } it "includes dirty modules into backend class and model class" do - expect(backend_class).to receive(:include).with(Mobility::Backend::Sequel::Dirty) - methods = instance_double(Mobility::Backend::Sequel::Dirty::MethodsBuilder) - expect(Mobility::Backend::Sequel::Dirty::MethodsBuilder).to receive(:new).with("title").and_return(methods) + expect(backend_class).to receive(:include).with(Mobility::Plugins::Sequel::Dirty) + methods = instance_double(Mobility::Plugins::Sequel::Dirty::MethodsBuilder) + expect(Mobility::Plugins::Sequel::Dirty::MethodsBuilder).to receive(:new).with("title").and_return(methods) expect(model_class).to receive(:include).with(methods) described_class.apply(attributes, true) end @@ -57,8 +57,8 @@ context "optoin value is falsey" do let(:attributes) { instance_double(Mobility::Attributes) } - it "does not include Mobility::FallthroughAccessors" do - expect(Mobility::FallthroughAccessors).not_to receive(:apply) + it "does not include Mobility::Plugins::FallthroughAccessors" do + expect(Mobility::Plugins::FallthroughAccessors).not_to receive(:apply) described_class.apply(attributes, false) end diff --git a/spec/mobility/backend/fallbacks_spec.rb b/spec/mobility/plugins/fallbacks_spec.rb similarity index 98% rename from spec/mobility/backend/fallbacks_spec.rb rename to spec/mobility/plugins/fallbacks_spec.rb index 1f193c5bf..0acfe7da6 100644 --- a/spec/mobility/backend/fallbacks_spec.rb +++ b/spec/mobility/plugins/fallbacks_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe Mobility::Backend::Fallbacks do +describe Mobility::Plugins::Fallbacks do describe "when included into a class" do let(:backend_class) do backend_class = stub_const 'MyBackend', Class.new diff --git a/spec/mobility/fallthrough_accessors_spec.rb b/spec/mobility/plugins/fallthrough_accessors_spec.rb similarity index 96% rename from spec/mobility/fallthrough_accessors_spec.rb rename to spec/mobility/plugins/fallthrough_accessors_spec.rb index d0081543d..5cfecd518 100644 --- a/spec/mobility/fallthrough_accessors_spec.rb +++ b/spec/mobility/plugins/fallthrough_accessors_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe Mobility::FallthroughAccessors do +describe Mobility::Plugins::FallthroughAccessors do describe "when included into a class" do let(:model_class) do klass = Class.new do diff --git a/spec/mobility/locale_accessors_spec.rb b/spec/mobility/plugins/locale_accessors_spec.rb similarity index 99% rename from spec/mobility/locale_accessors_spec.rb rename to spec/mobility/plugins/locale_accessors_spec.rb index 614a8a721..dffe79e9d 100644 --- a/spec/mobility/locale_accessors_spec.rb +++ b/spec/mobility/plugins/locale_accessors_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe Mobility::LocaleAccessors do +describe Mobility::Plugins::LocaleAccessors do describe "when included into a class" do let(:base_model_class) do Class.new do diff --git a/spec/mobility/backend/presence_spec.rb b/spec/mobility/plugins/presence_spec.rb similarity index 97% rename from spec/mobility/backend/presence_spec.rb rename to spec/mobility/plugins/presence_spec.rb index bbf91ed5e..6305143f1 100644 --- a/spec/mobility/backend/presence_spec.rb +++ b/spec/mobility/plugins/presence_spec.rb @@ -1,12 +1,12 @@ require "spec_helper" -describe Mobility::Backend::Presence do +describe Mobility::Plugins::Presence do describe "when included into a class" do let(:backend_double) { double("backend") } let(:backend) { backend_class.new("model", "attribute") } let(:backend_class) do backend_double_ = backend_double - backend_class = Class.new(Mobility::Backend::Null) do + backend_class = Class.new(Mobility::Backends::Null) do define_method :read do |*args| backend_double_.read(*args) end diff --git a/spec/mobility/backend/sequel/dirty_spec.rb b/spec/mobility/plugins/sequel/dirty_spec.rb similarity index 98% rename from spec/mobility/backend/sequel/dirty_spec.rb rename to spec/mobility/plugins/sequel/dirty_spec.rb index 444e11484..34f0e6c0d 100644 --- a/spec/mobility/backend/sequel/dirty_spec.rb +++ b/spec/mobility/plugins/sequel/dirty_spec.rb @@ -1,8 +1,8 @@ require "spec_helper" -describe Mobility::Backend::Sequel::Dirty, orm: :sequel do +describe Mobility::Plugins::Sequel::Dirty, orm: :sequel do let(:backend_class) do - Class.new(Mobility::Backend::Null) do + Class.new(Mobility::Backends::Null) do def read(locale, **options) values[locale] end diff --git a/spec/performance/attributes_spec.rb b/spec/performance/attributes_spec.rb index 14d02695c..c703038c7 100644 --- a/spec/performance/attributes_spec.rb +++ b/spec/performance/attributes_spec.rb @@ -13,7 +13,7 @@ include Mobility end attributes = described_class.new(:accessor, backend: :null) - expect { klass.include attributes }.to allocate_under(30).objects + expect { klass.include attributes }.to allocate_under(100).objects } end diff --git a/spec/support/shared_examples/querying_examples.rb b/spec/support/shared_examples/querying_examples.rb index e46da8344..f9c26ab74 100644 --- a/spec/support/shared_examples/querying_examples.rb +++ b/spec/support/shared_examples/querying_examples.rb @@ -317,7 +317,7 @@ # result which satisfies the second (or) condition. This is impossible to # avoid without modification of an earlier dataset, which is probably not # a good idea. - skip "Not supported by #{backend_class.name}" if [Mobility::Backend::Sequel::Table, Mobility::Backend::Sequel::KeyValue].include?(backend_class) + skip "Not supported by #{backend_class.name}" if [Mobility::Backends::Sequel::Table, Mobility::Backends::Sequel::KeyValue].include?(backend_class) expect(query_scope.where(published: false).or(:published => true, attribute2 => "baz content")).to match_array([@instance2, @instance3]) end end