mobility 0.1.20 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +2 -0
  4. data/CHANGELOG.md +17 -0
  5. data/CONTRIBUTING.md +55 -0
  6. data/Gemfile +2 -0
  7. data/Gemfile.lock +2 -56
  8. data/README.md +64 -15
  9. data/Rakefile +17 -17
  10. data/lib/mobility.rb +43 -40
  11. data/lib/mobility/active_model.rb +0 -1
  12. data/lib/mobility/active_model/backend_resetter.rb +1 -1
  13. data/lib/mobility/active_record.rb +8 -15
  14. data/lib/mobility/active_record/backend_resetter.rb +2 -0
  15. data/lib/mobility/active_record/model_translation.rb +1 -1
  16. data/lib/mobility/active_record/string_translation.rb +2 -0
  17. data/lib/mobility/active_record/text_translation.rb +2 -0
  18. data/lib/mobility/attributes.rb +74 -71
  19. data/lib/mobility/backend.rb +64 -25
  20. data/lib/mobility/backend/orm_delegator.rb +17 -7
  21. data/lib/mobility/backend/stringify_locale.rb +18 -0
  22. data/lib/mobility/backend_resetter.rb +8 -5
  23. data/lib/mobility/backends.rb +4 -0
  24. data/lib/mobility/backends/active_record.rb +20 -0
  25. data/lib/mobility/{backend → backends}/active_record/column.rb +25 -13
  26. data/lib/mobility/{backend → backends}/active_record/column/query_methods.rb +5 -3
  27. data/lib/mobility/backends/active_record/hstore.rb +29 -0
  28. data/lib/mobility/{backend → backends}/active_record/hstore/query_methods.rb +2 -2
  29. data/lib/mobility/{backend → backends}/active_record/jsonb.rb +6 -6
  30. data/lib/mobility/{backend → backends}/active_record/jsonb/query_methods.rb +4 -2
  31. data/lib/mobility/{backend → backends}/active_record/key_value.rb +10 -44
  32. data/lib/mobility/{backend → backends}/active_record/key_value/query_methods.rb +4 -2
  33. data/lib/mobility/{backend/active_record/hash_valued.rb → backends/active_record/pg_hash.rb} +13 -21
  34. data/lib/mobility/{backend → backends}/active_record/query_methods.rb +2 -2
  35. data/lib/mobility/{backend → backends}/active_record/serialized.rb +12 -28
  36. data/lib/mobility/{backend → backends}/active_record/serialized/query_methods.rb +5 -8
  37. data/lib/mobility/{backend → backends}/active_record/table.rb +11 -60
  38. data/lib/mobility/{backend → backends}/active_record/table/query_methods.rb +5 -3
  39. data/lib/mobility/{backend → backends}/column.rb +8 -4
  40. data/lib/mobility/backends/hash_valued.rb +29 -0
  41. data/lib/mobility/{backend → backends}/hstore.rb +4 -4
  42. data/lib/mobility/{backend → backends}/jsonb.rb +4 -4
  43. data/lib/mobility/backends/key_value.rb +111 -0
  44. data/lib/mobility/{backend → backends}/null.rb +4 -4
  45. data/lib/mobility/backends/sequel.rb +20 -0
  46. data/lib/mobility/backends/sequel/column.rb +52 -0
  47. data/lib/mobility/{backend → backends}/sequel/column/query_methods.rb +5 -3
  48. data/lib/mobility/backends/sequel/hstore.rb +29 -0
  49. data/lib/mobility/{backend → backends}/sequel/hstore/query_methods.rb +4 -3
  50. data/lib/mobility/{backend → backends}/sequel/jsonb.rb +6 -6
  51. data/lib/mobility/{backend → backends}/sequel/jsonb/query_methods.rb +4 -3
  52. data/lib/mobility/{backend → backends}/sequel/key_value.rb +28 -39
  53. data/lib/mobility/{backend → backends}/sequel/key_value/query_methods.rb +4 -5
  54. data/lib/mobility/backends/sequel/pg_hash.rb +46 -0
  55. data/lib/mobility/{backend → backends}/sequel/postgres_query_methods.rb +1 -2
  56. data/lib/mobility/{backend → backends}/sequel/query_methods.rb +6 -4
  57. data/lib/mobility/{backend → backends}/sequel/serialized.rb +17 -38
  58. data/lib/mobility/backends/sequel/serialized/query_methods.rb +17 -0
  59. data/lib/mobility/{backend → backends}/sequel/table.rb +29 -60
  60. data/lib/mobility/{backend → backends}/sequel/table/query_methods.rb +5 -3
  61. data/lib/mobility/{backend → backends}/serialized.rb +27 -5
  62. data/lib/mobility/{backend → backends}/table.rb +69 -29
  63. data/lib/mobility/configuration.rb +40 -0
  64. data/lib/mobility/{orm.rb → loaded.rb} +0 -0
  65. data/lib/mobility/plugins.rb +35 -0
  66. data/lib/mobility/plugins/active_model.rb +6 -0
  67. data/lib/mobility/plugins/active_model/dirty.rb +81 -0
  68. data/lib/mobility/plugins/active_record.rb +6 -0
  69. data/lib/mobility/plugins/active_record/dirty.rb +59 -0
  70. data/lib/mobility/plugins/cache.rb +54 -0
  71. data/lib/mobility/plugins/cache/translation_cacher.rb +40 -0
  72. data/lib/mobility/plugins/default.rb +73 -0
  73. data/lib/mobility/plugins/dirty.rb +61 -0
  74. data/lib/mobility/{backend → plugins}/fallbacks.rb +36 -31
  75. data/lib/mobility/plugins/fallthrough_accessors.rb +66 -0
  76. data/lib/mobility/plugins/locale_accessors.rb +84 -0
  77. data/lib/mobility/{backend → plugins}/presence.rb +15 -6
  78. data/lib/mobility/plugins/sequel.rb +6 -0
  79. data/lib/mobility/plugins/sequel/dirty.rb +59 -0
  80. data/lib/mobility/sequel.rb +5 -14
  81. data/lib/mobility/sequel/backend_resetter.rb +4 -6
  82. data/lib/mobility/sequel/column_changes.rb +4 -4
  83. data/lib/mobility/sequel/model_translation.rb +1 -1
  84. data/lib/mobility/sequel/string_translation.rb +2 -0
  85. data/lib/mobility/sequel/text_translation.rb +2 -0
  86. data/lib/mobility/translates.rb +1 -5
  87. data/lib/mobility/util.rb +126 -0
  88. data/lib/mobility/version.rb +1 -1
  89. data/lib/mobility/wrapper.rb +1 -1
  90. data/lib/rails/generators/mobility/translations_generator.rb +7 -3
  91. metadata +85 -55
  92. metadata.gz.sig +0 -0
  93. data/lib/mobility/backend/active_model.rb +0 -7
  94. data/lib/mobility/backend/active_model/dirty.rb +0 -95
  95. data/lib/mobility/backend/active_record.rb +0 -29
  96. data/lib/mobility/backend/active_record/dirty.rb +0 -54
  97. data/lib/mobility/backend/active_record/hstore.rb +0 -29
  98. data/lib/mobility/backend/cache.rb +0 -117
  99. data/lib/mobility/backend/dirty.rb +0 -38
  100. data/lib/mobility/backend/key_value.rb +0 -85
  101. data/lib/mobility/backend/sequel.rb +0 -29
  102. data/lib/mobility/backend/sequel/column.rb +0 -39
  103. data/lib/mobility/backend/sequel/dirty.rb +0 -57
  104. data/lib/mobility/backend/sequel/hash_valued.rb +0 -51
  105. data/lib/mobility/backend/sequel/hstore.rb +0 -29
  106. data/lib/mobility/backend/sequel/serialized/query_methods.rb +0 -20
  107. data/lib/mobility/core_ext/object.rb +0 -30
  108. data/lib/mobility/core_ext/string.rb +0 -16
  109. data/lib/mobility/fallthrough_accessors.rb +0 -57
  110. data/lib/mobility/locale_accessors.rb +0 -55
@@ -1,29 +0,0 @@
1
- module Mobility
2
- module Backend
3
- module Sequel
4
- autoload :Column, 'mobility/backend/sequel/column'
5
- autoload :Dirty, 'mobility/backend/sequel/dirty'
6
- autoload :Hstore, 'mobility/backend/sequel/hstore'
7
- autoload :Jsonb, 'mobility/backend/sequel/jsonb'
8
- autoload :KeyValue, 'mobility/backend/sequel/key_value'
9
- autoload :Serialized, 'mobility/backend/sequel/serialized'
10
- autoload :Table, 'mobility/backend/sequel/table'
11
- autoload :QueryMethods, 'mobility/backend/sequel/query_methods'
12
-
13
- def setup_query_methods(query_methods)
14
- setup do |attributes, options|
15
- extend(Module.new do
16
- define_method ::Mobility.query_method do
17
- super().with_extend(query_methods.new(attributes, options))
18
- end
19
- end)
20
- end
21
- end
22
-
23
- def self.included(backend_class)
24
- backend_class.include(Backend)
25
- backend_class.extend(self)
26
- end
27
- end
28
- end
29
- end
@@ -1,39 +0,0 @@
1
- module Mobility
2
- module Backend
3
- =begin
4
-
5
- Implements the {Mobility::Backend::Column} backend for Sequel models.
6
-
7
- @note This backend disables the +locale_accessors+ option, which would
8
- otherwise interfere with column methods.
9
- =end
10
- class Sequel::Column
11
- include Sequel
12
- include Column
13
-
14
- require 'mobility/backend/sequel/column/query_methods'
15
-
16
- # @!group Backend Accessors
17
- # @!macro backend_reader
18
- def read(locale, **_)
19
- column = column(locale)
20
- model.send(column) if model.columns.include?(column)
21
- end
22
-
23
- # @!group Backend Accessors
24
- # @!macro backend_writer
25
- def write(locale, value, **_)
26
- column = column(locale)
27
- model.send("#{column}=", value) if model.columns.include?(column)
28
- end
29
-
30
- # @!group Backend Configuration
31
- def self.configure(options)
32
- options[:locale_accessors] = false
33
- end
34
- # @!endgroup
35
-
36
- setup_query_methods(QueryMethods)
37
- end
38
- end
39
- end
@@ -1,57 +0,0 @@
1
- module Mobility
2
- module Backend
3
- =begin
4
-
5
- Dirty tracking for Sequel models which use the +Sequel::Plugins::Dirty+ plugin.
6
- Automatically includes dirty plugin in model class when enabled.
7
-
8
- @see http://sequel.jeremyevans.net/rdoc-plugins/index.html Sequel dirty plugin
9
-
10
- =end
11
- module Sequel::Dirty
12
- # @!group Backend Accessors
13
- # @!macro backend_writer
14
- # @param [Hash] options
15
- def write(locale, value, **options)
16
- locale_accessor = Mobility.normalize_locale_accessor(attribute, locale).to_sym
17
- if model.column_changes.has_key?(locale_accessor) && model.initial_values[locale_accessor] == value
18
- super
19
- [model.changed_columns, model.initial_values].each { |h| h.delete(locale_accessor) }
20
- elsif read(locale, options.merge(fallback: false)) != value
21
- model.will_change_column(locale_accessor)
22
- super
23
- end
24
- end
25
- # @!endgroup
26
-
27
- # @param [Class] backend_class Class of backend
28
- def self.included(backend_class)
29
- backend_class.extend(ClassMethods)
30
- end
31
-
32
- # Adds hook after {Backend::Setup#setup_model} to add dirty-tracking
33
- # methods for translated attributes onto model class.
34
- module ClassMethods
35
- # (see Mobility::Backend::Setup#setup_model)
36
- def setup_model(model_class, attributes, **options)
37
- super
38
- model_class.plugin :dirty
39
- model_class.class_eval do
40
- mod = Module.new do
41
- %w[initial_value column_change column_changed? reset_column].each do |method_name|
42
- define_method method_name do |column|
43
- if attributes.map(&:to_sym).include?(column)
44
- super(Mobility.normalize_locale_accessor(column).to_sym)
45
- else
46
- super(column)
47
- end
48
- end
49
- end
50
- end
51
- include mod
52
- end
53
- end
54
- end
55
- end
56
- end
57
- end
@@ -1,51 +0,0 @@
1
- module Mobility
2
- module Backend
3
- =begin
4
-
5
- Internal class used by Sequel backends that store values as a hash.
6
-
7
- =end
8
- class Sequel::HashValued
9
- include Sequel
10
-
11
- # @!macro backend_reader
12
- def read(locale, **_)
13
- translations[locale.to_s]
14
- end
15
-
16
- # @!macro backend_writer
17
- def write(locale, value, **_)
18
- translations[locale.to_s] = value
19
- end
20
-
21
- # @!group Cache Methods
22
- def translations
23
- model.send("#{attribute}_before_mobility")
24
- end
25
- alias_method :new_cache, :translations
26
-
27
- # @return [Boolean]
28
- def write_to_cache?
29
- true
30
- end
31
- # @!endgroup
32
-
33
- setup do |attributes, options|
34
- method_overrides = Module.new do
35
- define_method :initialize_set do |values|
36
- attributes.each { |attribute| send(:"#{attribute}_before_mobility=", {}) }
37
- super(values)
38
- end
39
- define_method :before_validation do
40
- attributes.each do |attribute|
41
- send("#{attribute}_before_mobility").delete_if { |_, v| v.blank? }
42
- end
43
- super()
44
- end
45
- end
46
- include method_overrides
47
- include Mobility::Sequel::ColumnChanges.new(attributes)
48
- end
49
- end
50
- end
51
- end
@@ -1,29 +0,0 @@
1
- require 'mobility/backend/sequel/hash_valued'
2
-
3
- module Mobility
4
- module Backend
5
- =begin
6
-
7
- Implements the {Mobility::Backend::Hstore} backend for Sequel models.
8
-
9
- @see Mobility::Backend::Sequel::HashValued
10
-
11
- =end
12
- class Sequel::Hstore < Sequel::HashValued
13
- require 'mobility/backend/sequel/hstore/query_methods'
14
-
15
- # @!group Backend Accessors
16
- # @!macro backend_reader
17
- # @!method read(locale, **options)
18
-
19
- # @!group Backend Accessors
20
- # @!macro backend_writer
21
- def write(locale, value, **_)
22
- translations[locale.to_s] = value && value.to_s
23
- end
24
- # @!endgroup
25
-
26
- setup_query_methods(QueryMethods)
27
- end
28
- end
29
- end
@@ -1,20 +0,0 @@
1
- module Mobility
2
- module Backend
3
- class Sequel::Serialized::QueryMethods < Sequel::QueryMethods
4
- def initialize(attributes, **)
5
- super
6
- attributes_extractor = @attributes_extractor
7
- cond_checker = @cond_checker = lambda do |cond|
8
- if i18n_keys = attributes_extractor.call(cond)
9
- raise ArgumentError,
10
- "You cannot query on mobility attributes translated with the Serialized backend (#{i18n_keys.join(", ")})."
11
- end
12
- end
13
-
14
- define_method :where do |*cond, &block|
15
- cond_checker.call(cond.first) || super(*cond, &block)
16
- end
17
- end
18
- end
19
- end
20
- end
@@ -1,30 +0,0 @@
1
- =begin
2
-
3
- Add +blank?+, +present?+ and +presence+ methods to +Object+ class if
4
- activesupport cannot be loaded.
5
-
6
- =end
7
- class Object
8
- def blank?
9
- respond_to?(:empty?) ? !!empty? : !self
10
- end
11
-
12
- def present?
13
- !blank?
14
- end
15
-
16
- def presence
17
- self if present?
18
- end
19
- end
20
-
21
- =begin
22
-
23
- Add +blank?+ method to +NilClass+ in case activesupport cannot be loaded.
24
-
25
- =end
26
- class NilClass
27
- def blank?
28
- true
29
- end
30
- end
@@ -1,16 +0,0 @@
1
- =begin
2
-
3
- Add String methods +camelize+ and +present?+ to +String+ if activesupport
4
- cannot be loaded.
5
-
6
- =end
7
- class String
8
- # paraphrased from activesupport
9
- def camelize
10
- sub(/^[a-z\d]*/) { $&.capitalize }.gsub(/(?:_|(\/))([a-z\d]*)/) { "#{$1}#{$2.capitalize}" }.gsub('/', '::')
11
- end
12
-
13
- def present?
14
- !blank?
15
- end
16
- end
@@ -1,57 +0,0 @@
1
- # frozen-string-literal: true
2
-
3
- module Mobility
4
- =begin
5
-
6
- Defines +method_missing+ and +respond_to_missing?+ methods for a set of
7
- attributes such that a method call using a locale accessor, like:
8
-
9
- article.title_pt_br
10
-
11
- will return the value of +article.title+ with the locale set to +pt-BR+ around
12
- the method call. The class is called "FallthroughAccessors" because when
13
- included in a model class, locale-specific methods will be available even if
14
- not explicitly defined with the +locale_accessors+ option.
15
-
16
- This is a less efficient (but more open-ended) implementation of locale
17
- accessors, for use in cases where the locales to be used are not known when the
18
- model class is generated.
19
-
20
- @example Using fallthrough locales on a plain old ruby class
21
- class Post
22
- def title
23
- "title in #{Mobility.locale}"
24
- end
25
- include Mobility::FallthroughAccessors.new("title")
26
- end
27
-
28
- Mobility.locale = :en
29
- post = Post.new
30
- post.title
31
- #=> "title in en"
32
- post.title_fr
33
- #=> "title in fr"
34
-
35
- =end
36
- class FallthroughAccessors < Module
37
- # @param [String] One or more attributes
38
- def initialize(*attributes)
39
- method_name_regex = /\A(#{attributes.join('|'.freeze)})_([a-z]{2}(_[a-z]{2})?)(=?|\??)\z/.freeze
40
-
41
- define_method :method_missing do |method_name, *arguments, &block|
42
- if method_name =~ method_name_regex
43
- attribute = $1.to_sym
44
- locale, suffix = $2.split('_'.freeze)
45
- locale = "#{locale}-#{suffix.upcase}".freeze if suffix
46
- Mobility.with_locale(locale) { public_send("#{attribute}#{$4}".freeze, *arguments) }
47
- else
48
- super(method_name, *arguments, &block)
49
- end
50
- end
51
-
52
- define_method :respond_to_missing? do |method_name, include_private = false|
53
- (method_name =~ method_name_regex) || super(method_name, include_private)
54
- end
55
- end
56
- end
57
- end
@@ -1,55 +0,0 @@
1
- # frozen-string-literal: true
2
-
3
- module Mobility
4
- =begin
5
-
6
- Defines methods for a set of locales to access translated attributes in those
7
- locales directly with a method call, using a suffix including the locale:
8
-
9
- article.title_pt_br
10
-
11
- If no locales are passed as an option to the initializer,
12
- +I18n.available_locales+ will be used by default.
13
-
14
- @example
15
- class Post
16
- def title
17
- "title in #{Mobility.locale}"
18
- end
19
- include Mobility::LocaleAccessors.new("title", locales: [:en, :fr])
20
- end
21
-
22
- Mobility.locale = :en
23
- post = Post.new
24
- post.title
25
- #=> "title in en"
26
- post.title_fr
27
- #=> "title in fr"
28
-
29
- =end
30
- class LocaleAccessors < Module
31
- # @param [String] One or more attributes
32
- # @param [Array<Symbol>] Locales
33
- def initialize(*attributes, locales: I18n.available_locales)
34
- warning_message = "locale passed as option to locale accessor will be ignored".freeze
35
-
36
- attributes.each do |attribute|
37
- locales.each do |locale|
38
- normalized_locale = Mobility.normalize_locale(locale)
39
- define_method "#{attribute}_#{normalized_locale}" do |**options|
40
- warn warning_message if options.delete(:locale)
41
- Mobility.with_locale(locale) { send(attribute, options) }
42
- end
43
- define_method "#{attribute}_#{normalized_locale}?" do |**options|
44
- warn warning_message if options.delete(:locale)
45
- Mobility.with_locale(locale) { send("#{attribute}?", options) }
46
- end
47
- define_method "#{attribute}_#{normalized_locale}=" do |value, **options|
48
- warn warning_message if options.delete(:locale)
49
- Mobility.with_locale(locale) { send("#{attribute}=", value, options) }
50
- end
51
- end
52
- end
53
- end
54
- end
55
- end