serial_translator 0.0.9 → 1.0.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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -4
- data/README.md +55 -9
- data/lib/serial_translator.rb +1 -2
- data/lib/serial_translator/serial_translator_length_validator.rb +36 -0
- data/lib/serial_translator/serial_translator_presence_validator.rb +9 -0
- data/lib/serial_translator/version.rb +1 -1
- data/serial_translator.gemspec +3 -2
- data/spec/lib/serial_translator/serial_translator_length_validator_spec.rb +99 -0
- data/spec/lib/serial_translator/serial_translator_presence_validator_spec.rb +38 -0
- data/spec/lib/serial_translator_spec.rb +2 -3
- data/spec/spec_helper.rb +2 -2
- data/spec/support/fake_object.rb +16 -21
- metadata +27 -12
- data/lib/serial_translator/serial_translator_validator.rb +0 -48
- data/spec/lib/serial_translator/serial_translator_validator_spec.rb +0 -100
- data/spec/support/validations_matcher.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ddceed208a6817aa8b7484c890d2340ec50ba391
|
4
|
+
data.tar.gz: f68db01cd4a2e5c0c4a9fadaae0990830a3d6c52
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a7412fbf5664d5808690344dd63c58de0633490738e74a2f52cf83a578fc889ce73aa3fb00c15868f10fdccb86feac7f3272998d65ed8e2e56e1476de7b54e4a
|
7
|
+
data.tar.gz: ccae43bae3f7da4aad8daf684bb2639a5a2fb463201ba17fe9e37e432f15258c711c4667484712573206814a44ee88b5bd2359024d9b7f83846170a0963522ec
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,24 +1,70 @@
|
|
1
1
|
# SerialTranslator
|
2
2
|
|
3
|
-
|
3
|
+
[](http://badge.fury.io/rb/serial_translator)
|
4
|
+
[](https://travis-ci.org/betterplace/serial_translator)
|
5
|
+
[](https://gemnasium.com/betterplace/serial_translator)
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
-
[](https://travis-ci.org/betterplace/serial_translator)
|
7
|
+
Translate ActiveRecord object attributes without the use of additional models.
|
8
8
|
|
9
9
|
## Installation
|
10
10
|
|
11
|
-
Add
|
11
|
+
Add it to your Gemfile:
|
12
12
|
|
13
13
|
gem 'serial_translator'
|
14
14
|
|
15
|
-
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
Add a `*_translations` column to your table, e.g. `title_translations`.
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
class AddTitleTranslationsToBlogPosts < ActiveRecord::Migration
|
21
|
+
def change
|
22
|
+
add_column :blog_posts, :title_translations, :text
|
23
|
+
end
|
24
|
+
end
|
25
|
+
```
|
26
|
+
|
27
|
+
In your model, call `#serial_translator_for`.
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
class BlogPost < ActiveRecord::Base
|
31
|
+
serial_translator_for :title
|
32
|
+
# [...]
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
Now you can read and write `title_translations` or `title_#{locale}` or `title(locale)`.
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
blog_post = BlogPost.new
|
40
|
+
blog_post.title_translations = { de: 'Hallo Welt', en: 'Hello world' }
|
41
|
+
blog_post.title_en # => "Hello world"
|
42
|
+
blog_post.title(:en) # => "Hello world"
|
43
|
+
blog_post.translated_locales # => [:de, :en]
|
44
|
+
```
|
45
|
+
|
46
|
+
Setting or getting the field name without specifying a locale defaults to the current locale.
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
I18n.locale = :de
|
50
|
+
blog_post.title # => "Hallo Welt"
|
51
|
+
blog_post.title = 'Hey'
|
52
|
+
blog_post.title_translations # => { de: 'Hey', en: 'Hello world' }
|
53
|
+
```
|
54
|
+
|
55
|
+
So if you add a `title` field to a BlogPost form it will work on the title in the user’s locale by default. You can override this by setting the record’s `#current_translation_locale`.
|
56
|
+
|
57
|
+
Add length or presence validations if you want. They will use the same localization keys for error messages as the standard length and presence validations.
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
class BlogPost < ActiveRecord::Base
|
61
|
+
validates :title, serial_translator_presence: true
|
62
|
+
validates :text, serial_translator_length: { minimum: 100 }
|
63
|
+
end
|
64
|
+
```
|
16
65
|
|
17
|
-
$ bundle
|
18
66
|
|
19
|
-
## Usage
|
20
67
|
|
21
|
-
To be written.
|
22
68
|
|
23
69
|
## Contributing
|
24
70
|
|
data/lib/serial_translator.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'active_support'
|
2
2
|
require 'active_model'
|
3
|
-
|
4
|
-
require 'serial_translator/serial_translator_validator'
|
3
|
+
Dir[File.join(__dir__, '**', '*.rb')].each { |file| require file }
|
5
4
|
|
6
5
|
module SerialTranslator
|
7
6
|
extend ActiveSupport::Concern
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class SerialTranslator::SerialTranslatorLengthValidator < ActiveModel::Validations::LengthValidator
|
2
|
+
def validate_each(record, attribute, _value)
|
3
|
+
translations = record.__send__("#{attribute}_translations")&.values || []
|
4
|
+
translations = [nil] if translations.empty?
|
5
|
+
translations.each do |value|
|
6
|
+
next if options[:allow_blank] && value.to_s == '' ||
|
7
|
+
options[:allow_nil] && value.nil?
|
8
|
+
validate_translation(record, attribute, value)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# this is ActiveModel::Validations::LengthValidator#validate_each,
|
13
|
+
# only extended with more interpolation args in error_options
|
14
|
+
def validate_translation(record, attribute, value)
|
15
|
+
value_length = value.respond_to?(:length) ? value.length : value.to_s.length
|
16
|
+
error_options = options.except(*RESERVED_OPTIONS)
|
17
|
+
|
18
|
+
CHECKS.each do |key, validity_check|
|
19
|
+
next unless check_value = options[key]
|
20
|
+
|
21
|
+
if !value.nil? || skip_nil_check?(key)
|
22
|
+
next if value_length.send(validity_check, check_value)
|
23
|
+
end
|
24
|
+
|
25
|
+
error_options.merge!(count: check_value, actual_length: value_length)
|
26
|
+
key == :minimum && error_options[:difference] = check_value - value_length
|
27
|
+
key == :maximum && error_options[:difference] = value_length - check_value
|
28
|
+
|
29
|
+
default_message = options[MESSAGES[key]]
|
30
|
+
error_options[:message] ||= default_message if default_message
|
31
|
+
record.errors.add(attribute, MESSAGES[key], error_options)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def kind; :length end
|
36
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class SerialTranslator::SerialTranslatorPresenceValidator < ActiveModel::Validations::PresenceValidator
|
2
|
+
def validate_each(record, attribute, _value)
|
3
|
+
translations = record.__send__("#{attribute}_translations") || {}
|
4
|
+
return if translations.values.any?(&:present?)
|
5
|
+
record.errors.add_on_blank(attribute, options)
|
6
|
+
end
|
7
|
+
|
8
|
+
def kind; :presence end
|
9
|
+
end
|
data/serial_translator.gemspec
CHANGED
@@ -18,11 +18,12 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_dependency 'activemodel', '>=
|
22
|
-
spec.add_dependency 'activeresource', '>=
|
21
|
+
spec.add_dependency 'activemodel', '>= 4.0.0'
|
22
|
+
spec.add_dependency 'activeresource', '>= 4.0.0'
|
23
23
|
|
24
24
|
spec.add_development_dependency 'bundler', '~> 1.3'
|
25
25
|
spec.add_development_dependency 'rake'
|
26
26
|
spec.add_development_dependency 'rspec'
|
27
|
+
spec.add_development_dependency 'rspec-collection_matchers'
|
27
28
|
spec.add_development_dependency 'simplecov'
|
28
29
|
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SerialTranslator::SerialTranslatorLengthValidator do
|
4
|
+
let(:example) { FakeObject.new }
|
5
|
+
|
6
|
+
describe 'validation' do
|
7
|
+
it 'validates min length correctly' do
|
8
|
+
example.title = '123'
|
9
|
+
expect(example).to have(1).error_on(:title)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'validates max length correctly' do
|
13
|
+
example.title = 'f' * 26
|
14
|
+
expect(example).to have(1).error_on(:title)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'validates correctly if only a minimum is given' do
|
18
|
+
example.credits = 'f' * 99
|
19
|
+
expect(example).to have(1).error_on(:credits)
|
20
|
+
example.credits = 'f' * 100
|
21
|
+
expect(example).to have(:no).errors_on(:credits)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'validates correctly if only a maximum is given' do
|
25
|
+
example.imprint = 'f' * 101
|
26
|
+
expect(example).to have(1).error_on(:imprint)
|
27
|
+
example.imprint = 'f' * 100
|
28
|
+
expect(example).to have(:no).errors_on(:imprint)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'validates correctly if a specific value is given' do
|
32
|
+
example.subtitle = 'f' * 8
|
33
|
+
expect(example).to have(1).error_on(:subtitle)
|
34
|
+
example.subtitle = 'f' * 9
|
35
|
+
expect(example).to have(:no).errors_on(:subtitle)
|
36
|
+
example.subtitle = 'f' * 10
|
37
|
+
expect(example).to have(1).error_on(:subtitle)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'validates all translation values' do
|
41
|
+
example.title_translations = { en: '123', de: '123' }
|
42
|
+
expect(example).to have(2).errors_on(:title)
|
43
|
+
|
44
|
+
example.title_translations = { en: '123456', de: '123' }
|
45
|
+
expect(example).to have(1).error_on(:title)
|
46
|
+
|
47
|
+
example.title_translations = { en: '123', de: '123456' }
|
48
|
+
expect(example).to have(1).error_on(:title)
|
49
|
+
|
50
|
+
example.title_translations = { en: '123456', de: '123456' }
|
51
|
+
expect(example).to have(:no).errors_on(:title)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'validates correctly on language change as well' do
|
55
|
+
I18n.locale = :de
|
56
|
+
example.title = 'Valid foo'
|
57
|
+
expect(example).to have(:no).errors_on(:title)
|
58
|
+
|
59
|
+
I18n.locale = :en
|
60
|
+
example.title = ''
|
61
|
+
expect(example).to have(:no).errors_on(:title)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'ignores blank fields if allow_blank is true' do
|
65
|
+
example.summary_translations = { de: '' }
|
66
|
+
expect(example).to have(:no).errors_on(:summary)
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'ignores blank fields if only a maximum is given' do
|
70
|
+
example.credits_translations = { de: '' }
|
71
|
+
expect(example).to have(:no).errors_on(:imprint)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'does not ignore blank fields otherwise' do
|
75
|
+
example.title_translations = { de: '' }
|
76
|
+
expect(example).to have(1).error_on(:title)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'ignores nil if allow_nil is true' do
|
80
|
+
example.subtitle_translations = { de: nil }
|
81
|
+
expect(example).to have(:no).errors_on(:subtitle)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'ignores nil if only a maximum is given' do
|
85
|
+
example.credits_translations = { de: nil }
|
86
|
+
expect(example).to have(:no).errors_on(:imprint)
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'does not ignore nil otherwise' do
|
90
|
+
example.title_translations = { de: nil }
|
91
|
+
expect(example).to have(1).error_on(:title)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'is of kind "length"' do
|
96
|
+
expect(described_class.new(attributes: %i(foo), in: 1..2).kind)
|
97
|
+
.to eq :length
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SerialTranslator::SerialTranslatorPresenceValidator do
|
4
|
+
let(:example) { FakeObject.new }
|
5
|
+
|
6
|
+
describe 'validation' do
|
7
|
+
it 'validates presence correctly if attribute is nil' do
|
8
|
+
example.description = nil
|
9
|
+
expect(example).to have(1).error_on(:description)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'validates presence correctly if attribute is empty' do
|
13
|
+
example.description = ''
|
14
|
+
expect(example).to have(1).error_on(:description)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'has no error if everything is fine' do
|
18
|
+
example.description = 'This is a nice foo thing'
|
19
|
+
expect(example).to have(:no).errors_on(:description)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'is valid if any language has a value' do
|
23
|
+
example.description_translations = { en: '', de: '' }
|
24
|
+
expect(example).to have(1).error_on(:description)
|
25
|
+
|
26
|
+
example.description_translations = { en: '', de: 'foobar' }
|
27
|
+
expect(example).to have(:no).errors_on(:description)
|
28
|
+
|
29
|
+
example.description_translations = { en: 'foobar', de: nil }
|
30
|
+
expect(example).to have(:no).errors_on(:description)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'is of kind "presence"' do
|
35
|
+
expect(described_class.new(attributes: %i(foo)).kind)
|
36
|
+
.to eq :presence
|
37
|
+
end
|
38
|
+
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe SerialTranslator do
|
4
|
-
|
5
4
|
let(:object) { FakeObject.new }
|
6
5
|
|
7
6
|
describe 'getting a translated value' do
|
@@ -84,12 +83,12 @@ describe SerialTranslator do
|
|
84
83
|
describe 'writing an attribute with for a specific locale' do
|
85
84
|
it 'sets the value for the correct locale' do
|
86
85
|
object.title_de = 'Deutsch'
|
87
|
-
expect(object.title_translations).to eq(
|
86
|
+
expect(object.title_translations).to eq(de: 'Deutsch')
|
88
87
|
end
|
89
88
|
|
90
89
|
it 'works for complex locales as well' do
|
91
90
|
object.title_en_gb = 'Arrr'
|
92
|
-
expect(object.title_translations).to eq(
|
91
|
+
expect(object.title_translations).to eq('en-GB': 'Arrr')
|
93
92
|
end
|
94
93
|
end
|
95
94
|
|
data/spec/spec_helper.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'simplecov'
|
2
2
|
|
3
|
-
SimpleCov.
|
3
|
+
SimpleCov.profiles.define 'gem' do
|
4
4
|
add_filter '/spec/'
|
5
5
|
add_group 'Libraries', '/lib/'
|
6
6
|
end
|
@@ -9,5 +9,5 @@ SimpleCov.start 'gem'
|
|
9
9
|
require 'serial_translator'
|
10
10
|
require 'active_model'
|
11
11
|
require 'active_resource'
|
12
|
-
require 'support/validations_matcher'
|
13
12
|
require 'support/fake_object'
|
13
|
+
require 'rspec/collection_matchers'
|
data/spec/support/fake_object.rb
CHANGED
@@ -1,37 +1,32 @@
|
|
1
1
|
# This class is only used for testing purposes.
|
2
2
|
class FakeObject
|
3
3
|
include ActiveModel::Validations
|
4
|
+
include SerialTranslator
|
4
5
|
|
5
|
-
def self.serialize(*)
|
6
|
-
def self.before_save(*) ; end
|
6
|
+
def self.serialize(*); end
|
7
7
|
|
8
|
-
|
8
|
+
def self.before_save(*); end
|
9
9
|
|
10
10
|
# Has to be set in this context to test it correctly
|
11
11
|
I18n.available_locales = [:en, :de, :'en-GB']
|
12
12
|
|
13
|
-
|
14
|
-
@changes ||= []
|
15
|
-
end
|
16
|
-
|
17
|
-
def mark_change(attribute)
|
18
|
-
changes << attribute
|
19
|
-
end
|
13
|
+
TRANSLATED_ATTRIBUTES = %w(description title subtitle summary credits imprint)
|
20
14
|
|
21
|
-
|
22
|
-
mark_change :description_translations
|
23
|
-
end
|
15
|
+
serial_translator_for(*TRANSLATED_ATTRIBUTES)
|
24
16
|
|
25
|
-
|
26
|
-
|
17
|
+
TRANSLATED_ATTRIBUTES.map {|ta| "#{ta}_translations" }.each do |hash_name|
|
18
|
+
attr_accessor hash_name
|
19
|
+
define_method("#{hash_name}_will_change!") { changes << hash_name.to_sym }
|
27
20
|
end
|
28
21
|
|
29
|
-
def
|
30
|
-
|
22
|
+
def changes
|
23
|
+
@changes ||= []
|
31
24
|
end
|
32
25
|
|
33
|
-
|
34
|
-
|
35
|
-
validates :
|
36
|
-
validates :
|
26
|
+
validates :description, serial_translator_presence: true
|
27
|
+
validates :title, serial_translator_length: { within: 5..25 }
|
28
|
+
validates :subtitle, serial_translator_length: { is: 9, allow_nil: true }
|
29
|
+
validates :summary, serial_translator_length: { in: 5..25, allow_blank: true }
|
30
|
+
validates :credits, serial_translator_length: { minimum: 100 }
|
31
|
+
validates :imprint, serial_translator_length: { maximum: 100 }
|
37
32
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: serial_translator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- betterplace development team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-11-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 4.0.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 4.0.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activeresource
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 4.0.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 4.0.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec-collection_matchers
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: simplecov
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -109,14 +123,15 @@ files:
|
|
109
123
|
- README.md
|
110
124
|
- Rakefile
|
111
125
|
- lib/serial_translator.rb
|
112
|
-
- lib/serial_translator/
|
126
|
+
- lib/serial_translator/serial_translator_length_validator.rb
|
127
|
+
- lib/serial_translator/serial_translator_presence_validator.rb
|
113
128
|
- lib/serial_translator/version.rb
|
114
129
|
- serial_translator.gemspec
|
115
|
-
- spec/lib/serial_translator/
|
130
|
+
- spec/lib/serial_translator/serial_translator_length_validator_spec.rb
|
131
|
+
- spec/lib/serial_translator/serial_translator_presence_validator_spec.rb
|
116
132
|
- spec/lib/serial_translator_spec.rb
|
117
133
|
- spec/spec_helper.rb
|
118
134
|
- spec/support/fake_object.rb
|
119
|
-
- spec/support/validations_matcher.rb
|
120
135
|
homepage: http://www.betterplace.org
|
121
136
|
licenses:
|
122
137
|
- WTFPL
|
@@ -137,13 +152,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
137
152
|
version: '0'
|
138
153
|
requirements: []
|
139
154
|
rubyforge_project:
|
140
|
-
rubygems_version: 2.5.
|
155
|
+
rubygems_version: 2.5.2
|
141
156
|
signing_key:
|
142
157
|
specification_version: 4
|
143
158
|
summary: Translate attribute values without additional models
|
144
159
|
test_files:
|
145
|
-
- spec/lib/serial_translator/
|
160
|
+
- spec/lib/serial_translator/serial_translator_length_validator_spec.rb
|
161
|
+
- spec/lib/serial_translator/serial_translator_presence_validator_spec.rb
|
146
162
|
- spec/lib/serial_translator_spec.rb
|
147
163
|
- spec/spec_helper.rb
|
148
164
|
- spec/support/fake_object.rb
|
149
|
-
- spec/support/validations_matcher.rb
|
@@ -1,48 +0,0 @@
|
|
1
|
-
class SerialTranslator::SerialTranslatorValidator < ActiveModel::EachValidator
|
2
|
-
|
3
|
-
# SimpleForm inspects validators to find out how long
|
4
|
-
# a field may be.
|
5
|
-
def kind
|
6
|
-
options[:length].present? ? :length : :presence
|
7
|
-
end
|
8
|
-
|
9
|
-
# SimpleForm expects the options :maximum and :minimum to be present
|
10
|
-
# for length validations. This is why we inspect our range and set them
|
11
|
-
# if possible.
|
12
|
-
def initialize(options)
|
13
|
-
if length = options[:length]
|
14
|
-
length.is_a?(Range) or raise "Only range values are allowed for length"
|
15
|
-
options[:maximum] = length.max
|
16
|
-
options[:minimum] = length.min
|
17
|
-
end
|
18
|
-
super options
|
19
|
-
end
|
20
|
-
|
21
|
-
def validate_each(record, attribute, value)
|
22
|
-
options[:presence] and validate_presence(record, attribute)
|
23
|
-
options[:length] and validate_translation_lengths(record, attribute)
|
24
|
-
end
|
25
|
-
|
26
|
-
def validate_presence(record, attribute)
|
27
|
-
translations = record.__send__(:"#{attribute}_translations") || {}
|
28
|
-
translations.values.any?(&:present?) or record.errors.add_on_blank(attribute, options)
|
29
|
-
end
|
30
|
-
|
31
|
-
def validate_translation_lengths(record, attribute)
|
32
|
-
translations = record.__send__(:"#{attribute}_translations") || {}
|
33
|
-
|
34
|
-
translations.each do |locale, value|
|
35
|
-
validate_length(record, attribute, value)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def validate_length(record, attribute, value)
|
40
|
-
return if value.blank?
|
41
|
-
length = options[:length]
|
42
|
-
|
43
|
-
value_length = value.respond_to?(:length) ? value.length : value.to_s.length
|
44
|
-
|
45
|
-
value_length < length.min and record.errors.add(attribute, :too_short, count: length.min)
|
46
|
-
value_length > length.max and record.errors.add(attribute, :too_long, count: length.max)
|
47
|
-
end
|
48
|
-
end
|
@@ -1,100 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe SerialTranslator::SerialTranslatorValidator do
|
4
|
-
let(:example) { FakeObject.new }
|
5
|
-
|
6
|
-
describe 'presence validation' do
|
7
|
-
it 'validates presence correctly if attribute is nil' do
|
8
|
-
example.valid?
|
9
|
-
expect(example.errors[:description].size).to eq 1
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'validates presence correctly if attribute is empty' do
|
13
|
-
example.description = ''
|
14
|
-
example.valid?
|
15
|
-
expect(example.errors[:description].size).to eq 1
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'has no error if everything is fine' do
|
19
|
-
example.description = 'This is a nice foo thing'
|
20
|
-
example.valid?
|
21
|
-
expect(example.errors[:description].size).to eq 0
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'is valid if any language has a value' do
|
25
|
-
example.description_translations = { en: '', de: '' }
|
26
|
-
example.valid?
|
27
|
-
expect(example.errors[:description].size).to eq 1
|
28
|
-
|
29
|
-
example.description_translations = { en: '', de: 'foobar' }
|
30
|
-
example.valid?
|
31
|
-
expect(example.errors[:description].size).to eq 0
|
32
|
-
|
33
|
-
example.description_translations = { en: 'foobar', de: nil }
|
34
|
-
example.valid?
|
35
|
-
expect(example.errors[:description].size).to eq 0
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
describe 'length validation' do
|
40
|
-
it 'validates min length correctly' do
|
41
|
-
example.title = '123'
|
42
|
-
example.valid?
|
43
|
-
expect(example.errors[:title].size).to eq 1
|
44
|
-
end
|
45
|
-
|
46
|
-
it 'validates max length correctly' do
|
47
|
-
example.title = 'f' * 26
|
48
|
-
example.valid?
|
49
|
-
expect(example.errors[:title].size).to eq 1
|
50
|
-
end
|
51
|
-
|
52
|
-
it 'ignores blank fields' do
|
53
|
-
example.title = ''
|
54
|
-
example.valid?
|
55
|
-
expect(example.errors[:title].size).to eq 0
|
56
|
-
end
|
57
|
-
|
58
|
-
it 'validates all translation values' do
|
59
|
-
example.title_translations = { en: '123', de: '123' }
|
60
|
-
example.valid?
|
61
|
-
expect(example.errors[:title].size).to eq 2
|
62
|
-
|
63
|
-
example.title_translations = { en: '123456', de: '123' }
|
64
|
-
example.valid?
|
65
|
-
expect(example.errors[:title].size).to eq 1
|
66
|
-
|
67
|
-
example.title_translations = { en: '123', de: '123456' }
|
68
|
-
example.valid?
|
69
|
-
expect(example.errors[:title].size).to eq 1
|
70
|
-
|
71
|
-
example.title_translations = { en: '123456', de: '123456' }
|
72
|
-
example.valid?
|
73
|
-
expect(example.errors[:title].size).to eq 0
|
74
|
-
end
|
75
|
-
|
76
|
-
it 'validates correctly on language change as well' do
|
77
|
-
I18n.locale = :de
|
78
|
-
example.description = :something_to_make_it_pass_valid
|
79
|
-
example.title = 'Valid foo'
|
80
|
-
expect(example).to be_valid
|
81
|
-
|
82
|
-
I18n.locale = :en
|
83
|
-
example.title = ''
|
84
|
-
expect(example).to be_valid
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
describe '#kind' do
|
89
|
-
it 'returns length if length validation is set' do
|
90
|
-
validator = SerialTranslator::SerialTranslatorValidator.new(attributes: :foo, length: 1..2)
|
91
|
-
expect(validator.kind).to eq :length
|
92
|
-
end
|
93
|
-
|
94
|
-
it 'returns presence if it is no length validation' do
|
95
|
-
validator = SerialTranslator::SerialTranslatorValidator.new(attributes: :foo)
|
96
|
-
expect(validator.kind).to eq :presence
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
@@ -1,11 +0,0 @@
|
|
1
|
-
# Monkey patch errors_on matcher
|
2
|
-
module ::ActiveModel::Validations
|
3
|
-
def errors_on(attribute, options = {})
|
4
|
-
valid_args = [options[:context]].compact
|
5
|
-
self.valid?(*valid_args)
|
6
|
-
|
7
|
-
[self.errors[attribute]].flatten.compact
|
8
|
-
end
|
9
|
-
|
10
|
-
alias :error_on :errors_on
|
11
|
-
end
|