mobility 0.8.11 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CHANGELOG.md +69 -1
  5. data/Gemfile +50 -18
  6. data/Gemfile.lock +32 -75
  7. data/README.md +184 -92
  8. data/Rakefile +6 -4
  9. data/lib/mobility.rb +100 -168
  10. data/lib/mobility/backend.rb +27 -51
  11. data/lib/mobility/backends.rb +20 -0
  12. data/lib/mobility/backends/active_record.rb +4 -0
  13. data/lib/mobility/backends/active_record/column.rb +3 -1
  14. data/lib/mobility/backends/active_record/container.rb +10 -11
  15. data/lib/mobility/backends/active_record/hstore.rb +6 -4
  16. data/lib/mobility/backends/active_record/json.rb +5 -3
  17. data/lib/mobility/backends/active_record/jsonb.rb +5 -3
  18. data/lib/mobility/backends/active_record/key_value.rb +31 -13
  19. data/lib/mobility/backends/active_record/pg_hash.rb +1 -1
  20. data/lib/mobility/backends/active_record/serialized.rb +6 -0
  21. data/lib/mobility/backends/active_record/table.rb +17 -10
  22. data/lib/mobility/backends/column.rb +0 -6
  23. data/lib/mobility/backends/container.rb +10 -1
  24. data/lib/mobility/backends/hash.rb +39 -0
  25. data/lib/mobility/backends/hash_valued.rb +4 -0
  26. data/lib/mobility/backends/hstore.rb +0 -1
  27. data/lib/mobility/backends/json.rb +0 -1
  28. data/lib/mobility/backends/jsonb.rb +1 -2
  29. data/lib/mobility/backends/key_value.rb +31 -26
  30. data/lib/mobility/backends/null.rb +2 -0
  31. data/lib/mobility/backends/sequel.rb +37 -2
  32. data/lib/mobility/backends/sequel/column.rb +2 -0
  33. data/lib/mobility/backends/sequel/container.rb +11 -9
  34. data/lib/mobility/backends/sequel/hstore.rb +3 -1
  35. data/lib/mobility/backends/sequel/json.rb +3 -0
  36. data/lib/mobility/backends/sequel/jsonb.rb +3 -1
  37. data/lib/mobility/backends/sequel/key_value.rb +87 -18
  38. data/lib/mobility/backends/sequel/pg_hash.rb +6 -6
  39. data/lib/mobility/backends/sequel/serialized.rb +6 -0
  40. data/lib/mobility/backends/sequel/table.rb +22 -9
  41. data/lib/mobility/backends/serialized.rb +1 -3
  42. data/lib/mobility/backends/table.rb +39 -31
  43. data/lib/mobility/pluggable.rb +56 -0
  44. data/lib/mobility/plugin.rb +260 -0
  45. data/lib/mobility/plugins.rb +27 -24
  46. data/lib/mobility/plugins/active_model.rb +17 -0
  47. data/lib/mobility/plugins/active_model/cache.rb +26 -0
  48. data/lib/mobility/plugins/active_model/dirty.rb +119 -78
  49. data/lib/mobility/plugins/active_record.rb +37 -0
  50. data/lib/mobility/plugins/active_record/backend.rb +27 -0
  51. data/lib/mobility/plugins/active_record/cache.rb +28 -0
  52. data/lib/mobility/plugins/active_record/dirty.rb +34 -17
  53. data/lib/mobility/plugins/active_record/query.rb +43 -31
  54. data/lib/mobility/plugins/active_record/uniqueness_validation.rb +60 -0
  55. data/lib/mobility/plugins/arel.rb +125 -0
  56. data/lib/mobility/plugins/arel/nodes.rb +15 -0
  57. data/lib/mobility/plugins/arel/nodes/pg_ops.rb +134 -0
  58. data/lib/mobility/plugins/attribute_methods.rb +29 -20
  59. data/lib/mobility/plugins/attributes.rb +72 -0
  60. data/lib/mobility/plugins/backend.rb +161 -0
  61. data/lib/mobility/plugins/backend_reader.rb +34 -0
  62. data/lib/mobility/plugins/cache.rb +68 -26
  63. data/lib/mobility/plugins/default.rb +22 -17
  64. data/lib/mobility/plugins/dirty.rb +12 -33
  65. data/lib/mobility/plugins/fallbacks.rb +52 -44
  66. data/lib/mobility/plugins/fallthrough_accessors.rb +25 -25
  67. data/lib/mobility/plugins/locale_accessors.rb +22 -35
  68. data/lib/mobility/plugins/presence.rb +28 -21
  69. data/lib/mobility/plugins/query.rb +8 -17
  70. data/lib/mobility/plugins/reader.rb +50 -0
  71. data/lib/mobility/plugins/sequel.rb +34 -0
  72. data/lib/mobility/plugins/sequel/backend.rb +25 -0
  73. data/lib/mobility/plugins/sequel/cache.rb +24 -0
  74. data/lib/mobility/plugins/sequel/dirty.rb +34 -23
  75. data/lib/mobility/plugins/sequel/query.rb +21 -6
  76. data/lib/mobility/plugins/writer.rb +44 -0
  77. data/lib/mobility/translations.rb +95 -0
  78. data/lib/mobility/version.rb +12 -1
  79. data/lib/rails/generators/mobility/templates/initializer.rb +96 -78
  80. metadata +31 -42
  81. metadata.gz.sig +0 -0
  82. data/lib/mobility/active_model.rb +0 -4
  83. data/lib/mobility/active_model/backend_resetter.rb +0 -26
  84. data/lib/mobility/active_record.rb +0 -23
  85. data/lib/mobility/active_record/backend_resetter.rb +0 -26
  86. data/lib/mobility/active_record/model_translation.rb +0 -14
  87. data/lib/mobility/active_record/string_translation.rb +0 -10
  88. data/lib/mobility/active_record/text_translation.rb +0 -10
  89. data/lib/mobility/active_record/translation.rb +0 -14
  90. data/lib/mobility/active_record/uniqueness_validator.rb +0 -60
  91. data/lib/mobility/arel.rb +0 -49
  92. data/lib/mobility/arel/nodes.rb +0 -13
  93. data/lib/mobility/arel/nodes/pg_ops.rb +0 -132
  94. data/lib/mobility/arel/visitor.rb +0 -61
  95. data/lib/mobility/attributes.rb +0 -324
  96. data/lib/mobility/backend/orm_delegator.rb +0 -44
  97. data/lib/mobility/backend_resetter.rb +0 -50
  98. data/lib/mobility/configuration.rb +0 -138
  99. data/lib/mobility/fallbacks.rb +0 -28
  100. data/lib/mobility/interface.rb +0 -0
  101. data/lib/mobility/loaded.rb +0 -4
  102. data/lib/mobility/plugins/active_record/attribute_methods.rb +0 -38
  103. data/lib/mobility/plugins/cache/translation_cacher.rb +0 -40
  104. data/lib/mobility/sequel.rb +0 -9
  105. data/lib/mobility/sequel/backend_resetter.rb +0 -23
  106. data/lib/mobility/sequel/column_changes.rb +0 -28
  107. data/lib/mobility/sequel/hash_initializer.rb +0 -21
  108. data/lib/mobility/sequel/model_translation.rb +0 -20
  109. data/lib/mobility/sequel/sql.rb +0 -16
  110. data/lib/mobility/sequel/string_translation.rb +0 -10
  111. data/lib/mobility/sequel/text_translation.rb +0 -10
  112. data/lib/mobility/sequel/translation.rb +0 -53
  113. data/lib/mobility/translates.rb +0 -73
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
- module Mobility
3
- module Backend
4
- =begin
5
-
6
- Adds {#for} method to backend to return ORM-specific backend.
7
-
8
- @example KeyValue backend for AR model
9
- class Post < ActiveRecord::Base
10
- # ...
11
- end
12
- Mobility::Backends::KeyValue.for(Post)
13
- #=> Mobility::Backends::ActiveRecord::KeyValue
14
-
15
- =end
16
- module OrmDelegator
17
- # @param [Class] model_class Class of model
18
- # @return [Class] Class of backend to use for model
19
- def for(model_class)
20
- namespace = name.split('::')
21
- if Loaded::ActiveRecord && model_class < ::ActiveRecord::Base
22
- require_backend("active_record", namespace.last.underscore)
23
- const_get(namespace.insert(-2, "ActiveRecord").join("::"))
24
- elsif Loaded::Sequel && model_class < ::Sequel::Model
25
- require_backend("sequel", namespace.last.underscore)
26
- const_get(namespace.insert(-2, "Sequel").join("::"))
27
- else
28
- raise ArgumentError, "#{namespace.last} backend can only be used by ActiveRecord or Sequel models"
29
- end
30
- end
31
-
32
- private
33
-
34
- def require_backend(orm, backend)
35
- begin
36
- orm_backend = "mobility/backends/#{orm}/#{backend}"
37
- require orm_backend
38
- rescue LoadError => e
39
- raise unless e.message =~ /#{orm_backend}/
40
- end
41
- end
42
- end
43
- end
44
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mobility
4
- =begin
5
-
6
- Resets backend cache when reset events occur.
7
-
8
- @example Add trigger to call a method +my_backend_reset_method+ on backend instance when reset event(s) occurs on model
9
- resetter = Mobility::BackendResetter.for(MyModel).new(attributes) { my_backend_reset_method }
10
- MyModel.include(resetter)
11
-
12
- @see Mobility::ActiveRecord::BackendResetter
13
- @see Mobility::ActiveModel::BackendResetter
14
- @see Mobility::Sequel::BackendResetter
15
-
16
- =end
17
- class BackendResetter < Module
18
- # @param [Array<String>] attribute_names Names of attributes whose backends should be reset
19
- # @yield Backend to reset as context for block
20
- # @raise [ArgumentError] if no block is provided.
21
- def initialize(attribute_names, &block)
22
- raise ArgumentError, "block required" unless block_given?
23
- names = attribute_names.map(&:to_sym)
24
- @model_reset_method = Proc.new do
25
- names.each do |name|
26
- if @mobility_backends && @mobility_backends[name]
27
- @mobility_backends[name].instance_eval(&block)
28
- end
29
- end
30
- end
31
- end
32
-
33
- # Returns backend resetter class for model class
34
- # @param [Class] model_class Class of model to which backend resetter will be applied
35
- def self.for(model_class)
36
- if Loaded::ActiveRecord && model_class < ::ActiveRecord::Base
37
- require "mobility/active_record/backend_resetter"
38
- ActiveRecord::BackendResetter
39
- elsif Loaded::ActiveRecord && model_class.ancestors.include?(::ActiveModel::Dirty)
40
- require "mobility/active_model/backend_resetter"
41
- ActiveModel::BackendResetter
42
- elsif Loaded::Sequel && model_class < ::Sequel::Model
43
- require "mobility/sequel/backend_resetter"
44
- Sequel::BackendResetter
45
- else
46
- self
47
- end
48
- end
49
- end
50
- end
@@ -1,138 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mobility
4
- =begin
5
-
6
- Stores shared Mobility configuration referenced by all backends.
7
-
8
- =end
9
- class Configuration
10
- RESERVED_OPTION_KEYS = %i[backend model_class].freeze
11
-
12
- # Alias for mobility_accessor (defaults to +translates+)
13
- # @return [Symbol]
14
- attr_accessor :accessor_method
15
-
16
- # Name of query scope/dataset method (defaults to +i18n+)
17
- # @return [Symbol]
18
- attr_accessor :query_method
19
-
20
- # Default set of options. These will be merged with any backend options
21
- # when defining translated attributes (with +translates+). Default options
22
- # may not include the keys 'backend' or 'model_class'.
23
- # @return [Hash]
24
- attr_reader :default_options
25
-
26
- # @deprecated The default_options= setter has been deprecated. Set each
27
- # option on the default_options hash instead.
28
- def default_options=(options)
29
- warn %{
30
- WARNING: The default_options= setter has been deprecated.
31
- Set each option on the default_options hash instead, like this:
32
-
33
- config.default_options[:fallbacks] = { ... }
34
- config.default_options[:dirty] = true
35
- }
36
- if (keys = options.keys & RESERVED_OPTION_KEYS).present?
37
- raise ReservedOptionKey,
38
- "Default options may not contain the following reserved keys: #{keys.join(', ')}"
39
- else
40
- @default_options = options
41
- end
42
- end
43
-
44
- # Plugins to apply. Order of plugins is important, as this becomes the
45
- # order in which plugins modules are included into the backend class or
46
- # attributes instance.
47
- # @return [Array<Symbol>]
48
- attr_accessor :plugins
49
-
50
- # Generate new fallbacks instance
51
- # @note This method will call the proc defined in the variable set by the
52
- # +fallbacks_generator=+ setter, passing the first argument to its `call`
53
- # method. By default the generator returns an instance of
54
- # +I18n::Locale::Fallbacks+.
55
- # @param fallbacks [Hash] Fallbacks hash passed to generator
56
- # @return [I18n::Locale::Fallbacks]
57
- def new_fallbacks(fallbacks = {})
58
- @fallbacks_generator.call(fallbacks)
59
- end
60
-
61
- # Assign proc which, passed a set of fallbacks, returns a default fallbacks
62
- # instance. By default this is a proc which takes fallbacks and returns an
63
- # instance of +I18n::Locale::Fallbacks+.
64
- # @param [Proc] fallbacks generator
65
- attr_writer :fallbacks_generator
66
-
67
- # @deprecated Use {#new_fallbacks} instead.
68
- def default_fallbacks(fallbacks = {})
69
- warn %{
70
- WARNING: The default_fallbacks configuration getter has been renamed
71
- new_fallbacks to avoid confusion. The original method default_fallbacks will be
72
- removed in the next major version of Mobility.
73
- }
74
- new_fallbacks(fallbacks)
75
- end
76
-
77
- # @deprecated Use {#fallbacks_generator=} instead.
78
- def default_fallbacks=(fallbacks)
79
- warn %{
80
- WARNING: The default_fallbacks= configuration setter has been renamed
81
- fallbacks_generator= to avoid confusion. The original method
82
- default_fallbacks= will be removed in the next major version of Mobility.
83
- }
84
- self.fallbacks_generator = fallbacks
85
- end
86
-
87
- # Default backend to use (can be symbol or actual backend class)
88
- # @return [Symbol,Class]
89
- attr_accessor :default_backend
90
-
91
- # Returns set of default accessor locles to use (defaults to
92
- # +I18n.available_locales+)
93
- # @return [Array<Symbol>]
94
- def default_accessor_locales
95
- if @default_accessor_locales.is_a?(Proc)
96
- @default_accessor_locales.call
97
- else
98
- @default_accessor_locales
99
- end
100
- end
101
- attr_writer :default_accessor_locales
102
-
103
- def initialize
104
- @accessor_method = :translates
105
- @query_method = :i18n
106
- @fallbacks_generator = lambda { |fallbacks| Mobility::Fallbacks.build(fallbacks) }
107
- @default_accessor_locales = lambda { Mobility.available_locales }
108
- @default_options = Options[{
109
- cache: true,
110
- presence: true,
111
- query: true,
112
- default: Plugins::OPTION_UNSET
113
- }]
114
- @plugins = %i[
115
- query
116
- cache
117
- dirty
118
- fallbacks
119
- presence
120
- default
121
- attribute_methods
122
- fallthrough_accessors
123
- locale_accessors
124
- ]
125
- end
126
-
127
- class ReservedOptionKey < Exception; end
128
-
129
- class Options < Hash
130
- def []=(key, _)
131
- if RESERVED_OPTION_KEYS.include?(key)
132
- raise Configuration::ReservedOptionKey, "Default options may not contain the following reserved key: #{key}"
133
- end
134
- super
135
- end
136
- end
137
- end
138
- end
@@ -1,28 +0,0 @@
1
- module Mobility
2
- =begin
3
-
4
- Subclasses +I18n::Locale::Fallbacks+ such that instances of this class
5
- fall through to fallbacks defined in +I18n.fallbacks+. This allows models to
6
- customize fallbacks while still falling through to any fallbacks defined
7
- globally.
8
-
9
- =end
10
- class Fallbacks < ::I18n::Locale::Fallbacks
11
- # @param [Symbol] locale
12
- # @return [Array] locales
13
- def [](locale)
14
- super | I18n.fallbacks[locale]
15
- end
16
-
17
- # For this set of fallbacks, return a new fallbacks hash.
18
- # @param [Hash] fallbacks
19
- # @return [I18n::Locale::Fallbacks,Mobility::Fallbacks] fallbacks hash
20
- def self.build(fallbacks)
21
- if I18n.respond_to?(:fallbacks)
22
- new(fallbacks)
23
- else
24
- I18n::Locale::Fallbacks.new(fallbacks)
25
- end
26
- end
27
- end
28
- end
File without changes
@@ -1,4 +0,0 @@
1
- module Mobility
2
- module Loaded
3
- end
4
- end
@@ -1,38 +0,0 @@
1
- module Mobility
2
- module Plugins
3
- module ActiveRecord
4
- module TranslatedAttributes
5
- def translated_attributes
6
- {}
7
- end
8
-
9
- def attributes
10
- super.merge(translated_attributes)
11
- end
12
- end
13
-
14
- =begin
15
-
16
- Module builder adding translated attributes to #attributes hash on model
17
- instance. See {Mobility::Plugins::AttributeMethods} for further details.
18
-
19
- =end
20
- class AttributeMethods < Module
21
- def initialize(*attribute_names)
22
- include TranslatedAttributes
23
- define_method :translated_attributes do
24
- super().merge(attribute_names.inject({}) do |attributes, name|
25
- attributes.merge(name.to_s => send(name))
26
- end)
27
- end
28
- end
29
-
30
- def included(model_class)
31
- model_class.class_eval do
32
- define_method :untranslated_attributes, ::ActiveRecord::Base.instance_method(:attributes)
33
- end
34
- end
35
- end
36
- end
37
- end
38
- end
@@ -1,40 +0,0 @@
1
- module Mobility
2
- module Plugins
3
- module Cache
4
- =begin
5
-
6
- Creates a module to cache a given translation fetch method. The cacher defines
7
- private methods +cache+ and +clear_cache+ to access and clear, respectively, a
8
- translations hash.
9
-
10
- This cacher is used to cache translation values in {Mobility::Plugins::Cache},
11
- and also to cache translation *records* in {Mobility::Backends::Table} and
12
- {Mobility::Backends::KeyValue}.
13
-
14
- =end
15
- class TranslationCacher < Module
16
- # @param [Symbol] fetch_method Name of translation fetch method to cache
17
- def initialize(fetch_method)
18
- class_eval <<-EOM, __FILE__, __LINE__ + 1
19
- def #{fetch_method} locale, **options
20
- return super(locale, options) if options.delete(:cache) == false
21
- if cache.has_key?(locale)
22
- cache[locale]
23
- else
24
- cache[locale] = super(locale, options)
25
- end
26
- end
27
- EOM
28
-
29
- include CacheMethods
30
- end
31
-
32
- module CacheMethods
33
- private
34
- def cache; @cache ||= {}; end
35
- def clear_cache; @cache = {}; end
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,9 +0,0 @@
1
- module Mobility
2
- =begin
3
-
4
- Module loading Sequel-specific classes for Mobility models.
5
-
6
- =end
7
- module Sequel
8
- end
9
- end
@@ -1,23 +0,0 @@
1
- module Mobility
2
- module Sequel
3
- =begin
4
-
5
- Backend resetter for Sequel models. Triggers backend reset when +refresh+
6
- method is called.
7
-
8
- =end
9
- class BackendResetter < Mobility::BackendResetter
10
-
11
- # (see Mobility::BackendResetter#initialize)
12
- def initialize(attribute_names, &block)
13
- super
14
-
15
- model_reset_method = @model_reset_method
16
-
17
- define_method :refresh do
18
- super().tap { instance_eval(&model_reset_method) }
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mobility
4
- module Sequel
5
- =begin
6
-
7
- Internal class used to force Sequel model to notice changes when mobility
8
- setter method is called.
9
-
10
- =end
11
- class ColumnChanges < Module
12
- # @param [Array<String>] attributes Backend attributes
13
- def initialize(attributes, column_affix: "%s")
14
- attributes.each do |attribute|
15
- define_method "#{attribute}=" do |value, **options|
16
- if !options[:super] && send(attribute) != value
17
- locale = options[:locale] || Mobility.locale
18
- column = (column_affix % attribute).to_sym
19
- attribute_with_locale = :"#{attribute}_#{Mobility.normalize_locale(locale)}"
20
- @changed_columns = changed_columns | [column, attribute.to_sym, attribute_with_locale]
21
- end
22
- super(value, **options)
23
- end
24
- end
25
- end
26
- end
27
- end
28
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mobility
4
- module Sequel
5
- =begin
6
-
7
- Internal class used to initialize column value(s) by default to a hash.
8
-
9
- =end
10
- class HashInitializer < Module
11
- def initialize(*columns)
12
- class_eval <<-EOM, __FILE__, __LINE__ + 1
13
- def initialize_set(values)
14
- #{columns.map { |c| "self[:#{c}] = {}" }.join(';')}
15
- super
16
- end
17
- EOM
18
- end
19
- end
20
- end
21
- end
@@ -1,20 +0,0 @@
1
- module Mobility
2
- module Sequel
3
- =begin
4
-
5
- Module included in translation class dynamically generated by
6
- {Backends::Sequel::Table} backend.
7
-
8
- =end
9
- module ModelTranslation
10
- def self.included(base)
11
- base.plugin :validation_helpers
12
- end
13
-
14
- def validate
15
- super
16
- validates_presence [:locale]
17
- end
18
- end
19
- end
20
- end