mobility 0.1.20 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +2 -0
  4. data/CHANGELOG.md +17 -0
  5. data/CONTRIBUTING.md +55 -0
  6. data/Gemfile +2 -0
  7. data/Gemfile.lock +2 -56
  8. data/README.md +64 -15
  9. data/Rakefile +17 -17
  10. data/lib/mobility.rb +43 -40
  11. data/lib/mobility/active_model.rb +0 -1
  12. data/lib/mobility/active_model/backend_resetter.rb +1 -1
  13. data/lib/mobility/active_record.rb +8 -15
  14. data/lib/mobility/active_record/backend_resetter.rb +2 -0
  15. data/lib/mobility/active_record/model_translation.rb +1 -1
  16. data/lib/mobility/active_record/string_translation.rb +2 -0
  17. data/lib/mobility/active_record/text_translation.rb +2 -0
  18. data/lib/mobility/attributes.rb +74 -71
  19. data/lib/mobility/backend.rb +64 -25
  20. data/lib/mobility/backend/orm_delegator.rb +17 -7
  21. data/lib/mobility/backend/stringify_locale.rb +18 -0
  22. data/lib/mobility/backend_resetter.rb +8 -5
  23. data/lib/mobility/backends.rb +4 -0
  24. data/lib/mobility/backends/active_record.rb +20 -0
  25. data/lib/mobility/{backend → backends}/active_record/column.rb +25 -13
  26. data/lib/mobility/{backend → backends}/active_record/column/query_methods.rb +5 -3
  27. data/lib/mobility/backends/active_record/hstore.rb +29 -0
  28. data/lib/mobility/{backend → backends}/active_record/hstore/query_methods.rb +2 -2
  29. data/lib/mobility/{backend → backends}/active_record/jsonb.rb +6 -6
  30. data/lib/mobility/{backend → backends}/active_record/jsonb/query_methods.rb +4 -2
  31. data/lib/mobility/{backend → backends}/active_record/key_value.rb +10 -44
  32. data/lib/mobility/{backend → backends}/active_record/key_value/query_methods.rb +4 -2
  33. data/lib/mobility/{backend/active_record/hash_valued.rb → backends/active_record/pg_hash.rb} +13 -21
  34. data/lib/mobility/{backend → backends}/active_record/query_methods.rb +2 -2
  35. data/lib/mobility/{backend → backends}/active_record/serialized.rb +12 -28
  36. data/lib/mobility/{backend → backends}/active_record/serialized/query_methods.rb +5 -8
  37. data/lib/mobility/{backend → backends}/active_record/table.rb +11 -60
  38. data/lib/mobility/{backend → backends}/active_record/table/query_methods.rb +5 -3
  39. data/lib/mobility/{backend → backends}/column.rb +8 -4
  40. data/lib/mobility/backends/hash_valued.rb +29 -0
  41. data/lib/mobility/{backend → backends}/hstore.rb +4 -4
  42. data/lib/mobility/{backend → backends}/jsonb.rb +4 -4
  43. data/lib/mobility/backends/key_value.rb +111 -0
  44. data/lib/mobility/{backend → backends}/null.rb +4 -4
  45. data/lib/mobility/backends/sequel.rb +20 -0
  46. data/lib/mobility/backends/sequel/column.rb +52 -0
  47. data/lib/mobility/{backend → backends}/sequel/column/query_methods.rb +5 -3
  48. data/lib/mobility/backends/sequel/hstore.rb +29 -0
  49. data/lib/mobility/{backend → backends}/sequel/hstore/query_methods.rb +4 -3
  50. data/lib/mobility/{backend → backends}/sequel/jsonb.rb +6 -6
  51. data/lib/mobility/{backend → backends}/sequel/jsonb/query_methods.rb +4 -3
  52. data/lib/mobility/{backend → backends}/sequel/key_value.rb +28 -39
  53. data/lib/mobility/{backend → backends}/sequel/key_value/query_methods.rb +4 -5
  54. data/lib/mobility/backends/sequel/pg_hash.rb +46 -0
  55. data/lib/mobility/{backend → backends}/sequel/postgres_query_methods.rb +1 -2
  56. data/lib/mobility/{backend → backends}/sequel/query_methods.rb +6 -4
  57. data/lib/mobility/{backend → backends}/sequel/serialized.rb +17 -38
  58. data/lib/mobility/backends/sequel/serialized/query_methods.rb +17 -0
  59. data/lib/mobility/{backend → backends}/sequel/table.rb +29 -60
  60. data/lib/mobility/{backend → backends}/sequel/table/query_methods.rb +5 -3
  61. data/lib/mobility/{backend → backends}/serialized.rb +27 -5
  62. data/lib/mobility/{backend → backends}/table.rb +69 -29
  63. data/lib/mobility/configuration.rb +40 -0
  64. data/lib/mobility/{orm.rb → loaded.rb} +0 -0
  65. data/lib/mobility/plugins.rb +35 -0
  66. data/lib/mobility/plugins/active_model.rb +6 -0
  67. data/lib/mobility/plugins/active_model/dirty.rb +81 -0
  68. data/lib/mobility/plugins/active_record.rb +6 -0
  69. data/lib/mobility/plugins/active_record/dirty.rb +59 -0
  70. data/lib/mobility/plugins/cache.rb +54 -0
  71. data/lib/mobility/plugins/cache/translation_cacher.rb +40 -0
  72. data/lib/mobility/plugins/default.rb +73 -0
  73. data/lib/mobility/plugins/dirty.rb +61 -0
  74. data/lib/mobility/{backend → plugins}/fallbacks.rb +36 -31
  75. data/lib/mobility/plugins/fallthrough_accessors.rb +66 -0
  76. data/lib/mobility/plugins/locale_accessors.rb +84 -0
  77. data/lib/mobility/{backend → plugins}/presence.rb +15 -6
  78. data/lib/mobility/plugins/sequel.rb +6 -0
  79. data/lib/mobility/plugins/sequel/dirty.rb +59 -0
  80. data/lib/mobility/sequel.rb +5 -14
  81. data/lib/mobility/sequel/backend_resetter.rb +4 -6
  82. data/lib/mobility/sequel/column_changes.rb +4 -4
  83. data/lib/mobility/sequel/model_translation.rb +1 -1
  84. data/lib/mobility/sequel/string_translation.rb +2 -0
  85. data/lib/mobility/sequel/text_translation.rb +2 -0
  86. data/lib/mobility/translates.rb +1 -5
  87. data/lib/mobility/util.rb +126 -0
  88. data/lib/mobility/version.rb +1 -1
  89. data/lib/mobility/wrapper.rb +1 -1
  90. data/lib/rails/generators/mobility/translations_generator.rb +7 -3
  91. metadata +85 -55
  92. metadata.gz.sig +0 -0
  93. data/lib/mobility/backend/active_model.rb +0 -7
  94. data/lib/mobility/backend/active_model/dirty.rb +0 -95
  95. data/lib/mobility/backend/active_record.rb +0 -29
  96. data/lib/mobility/backend/active_record/dirty.rb +0 -54
  97. data/lib/mobility/backend/active_record/hstore.rb +0 -29
  98. data/lib/mobility/backend/cache.rb +0 -117
  99. data/lib/mobility/backend/dirty.rb +0 -38
  100. data/lib/mobility/backend/key_value.rb +0 -85
  101. data/lib/mobility/backend/sequel.rb +0 -29
  102. data/lib/mobility/backend/sequel/column.rb +0 -39
  103. data/lib/mobility/backend/sequel/dirty.rb +0 -57
  104. data/lib/mobility/backend/sequel/hash_valued.rb +0 -51
  105. data/lib/mobility/backend/sequel/hstore.rb +0 -29
  106. data/lib/mobility/backend/sequel/serialized/query_methods.rb +0 -20
  107. data/lib/mobility/core_ext/object.rb +0 -30
  108. data/lib/mobility/core_ext/string.rb +0 -16
  109. data/lib/mobility/fallthrough_accessors.rb +0 -57
  110. data/lib/mobility/locale_accessors.rb +0 -55
@@ -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