virtus 1.0.3 → 1.0.4
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 +8 -5
- data/Changelog.md +7 -1
- data/Gemfile +14 -5
- data/README.md +40 -19
- data/Rakefile +13 -3
- data/lib/virtus/configuration.rb +10 -5
- data/lib/virtus/version.rb +1 -1
- data/spec/integration/collection_member_coercion_spec.rb +34 -13
- data/spec/integration/hash_attributes_coercion_spec.rb +5 -5
- data/spec/shared/freeze_method_behavior.rb +5 -2
- data/spec/shared/idempotent_method_behaviour.rb +1 -1
- data/spec/shared/options_class_method.rb +3 -3
- data/spec/spec_helper.rb +3 -18
- data/spec/unit/virtus/attribute/boolean/coerce_spec.rb +3 -3
- data/spec/unit/virtus/attribute/boolean/value_coerced_predicate_spec.rb +3 -3
- data/spec/unit/virtus/attribute/class_methods/build_spec.rb +48 -24
- data/spec/unit/virtus/attribute/class_methods/coerce_spec.rb +2 -2
- data/spec/unit/virtus/attribute/coerce_spec.rb +9 -9
- data/spec/unit/virtus/attribute/coercible_predicate_spec.rb +2 -2
- data/spec/unit/virtus/attribute/collection/class_methods/build_spec.rb +2 -2
- data/spec/unit/virtus/attribute/collection/coerce_spec.rb +5 -5
- data/spec/unit/virtus/attribute/custom_collection_spec.rb +8 -2
- data/spec/unit/virtus/attribute/defined_spec.rb +2 -2
- data/spec/unit/virtus/attribute/embedded_value/class_methods/build_spec.rb +30 -15
- data/spec/unit/virtus/attribute/embedded_value/coerce_spec.rb +25 -11
- data/spec/unit/virtus/attribute/get_spec.rb +2 -2
- data/spec/unit/virtus/attribute/hash/class_methods/build_spec.rb +7 -7
- data/spec/unit/virtus/attribute/hash/coerce_spec.rb +9 -9
- data/spec/unit/virtus/attribute/lazy_predicate_spec.rb +2 -2
- data/spec/unit/virtus/attribute/rename_spec.rb +6 -3
- data/spec/unit/virtus/attribute/required_predicate_spec.rb +2 -2
- data/spec/unit/virtus/attribute/set_default_value_spec.rb +43 -10
- data/spec/unit/virtus/attribute/set_spec.rb +1 -1
- data/spec/unit/virtus/attribute/value_coerced_predicate_spec.rb +2 -2
- data/spec/unit/virtus/attribute_set/append_spec.rb +2 -2
- data/spec/unit/virtus/attribute_set/define_reader_method_spec.rb +12 -11
- data/spec/unit/virtus/attribute_set/define_writer_method_spec.rb +13 -12
- data/spec/unit/virtus/attribute_set/each_spec.rb +3 -3
- data/spec/unit/virtus/attribute_set/element_reference_spec.rb +1 -1
- data/spec/unit/virtus/attribute_set/element_set_spec.rb +2 -2
- data/spec/unit/virtus/attribute_set/merge_spec.rb +2 -2
- data/spec/unit/virtus/attribute_set/reset_spec.rb +17 -8
- data/spec/unit/virtus/attribute_spec.rb +4 -4
- data/spec/unit/virtus/element_reader_spec.rb +1 -1
- data/spec/unit/virtus/freeze_spec.rb +10 -3
- data/spec/unit/virtus/model_spec.rb +35 -4
- data/spec/unit/virtus/set_default_attributes_spec.rb +10 -3
- data/spec/unit/virtus/value_object_spec.rb +13 -3
- data/virtus.gemspec +6 -4
- metadata +16 -8
- data/Gemfile.devtools +0 -71
- data/config/flay.yml +0 -3
- data/config/flog.yml +0 -2
- data/config/mutant.yml +0 -15
- data/config/reek.yml +0 -146
- data/config/yardstick.yml +0 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 934dc95c7d8fd79268fcf7e2303257cd72378ef9
|
4
|
+
data.tar.gz: dd9096d86a6df285b7b97f4cabab540afa72ed0b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9095639c91403b8193bfe71a9067da701298a5190f65bdef2ac0ea0aaef130cf819529b2a672e071b48857ce614082402048a9125658b4a6f129d432968239f7
|
7
|
+
data.tar.gz: ec1343ee430f0e6c6766c6e7a2457d116b7b4de00156f2ffe813989f1f62f96d712218756f750bfb45dc700552ba7999450ae243a3024ed1af3a5671e8a7b817
|
data/.travis.yml
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
language: ruby
|
2
2
|
before_install: gem install bundler
|
3
|
-
bundler_args: --without
|
4
|
-
script: "bundle exec rake
|
3
|
+
bundler_args: --without tools
|
4
|
+
script: "bundle exec rake spec"
|
5
|
+
env:
|
6
|
+
- CODECLIMATE_REPO_TOKEN=2b66fbb7c7c72503eb7841a479c0ad923f691729f4109b4aa8c9b4def1ebb42d
|
5
7
|
rvm:
|
6
|
-
- 1.9
|
7
|
-
- 2.0
|
8
|
-
- 2.1
|
8
|
+
- 1.9
|
9
|
+
- 2.0
|
10
|
+
- 2.1
|
11
|
+
- 2.2
|
9
12
|
- jruby
|
10
13
|
- rbx
|
11
14
|
- ruby-head
|
data/Changelog.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
# v1.0.4 2015-01-03
|
2
|
+
|
3
|
+
* [feature] Support for :required option when configuring a virtus module (solnic)
|
4
|
+
|
5
|
+
[Compare v1.0.3..v1.0.4](https://github.com/solnic/virtus/compare/v1.0.3...v1.0.4)
|
6
|
+
|
1
7
|
# v1.0.3 2014-07-24
|
2
8
|
|
3
9
|
* [improvement] Expose attribute name in the exception when in strict mode (ntl)
|
@@ -9,7 +15,7 @@
|
|
9
15
|
|
10
16
|
[Compare v1.0.2..v1.0.3](https://github.com/solnic/virtus/compare/v1.0.2...v1.0.3)
|
11
17
|
|
12
|
-
# v1.0.2
|
18
|
+
# v1.0.2 2013-12-03
|
13
19
|
|
14
20
|
* [improvement] Don’t override already-defined default values when freezing (amarshall)
|
15
21
|
* [improvement] Improved performance of `AttributeSet#each` (Antti)
|
data/Gemfile
CHANGED
@@ -3,10 +3,19 @@ source 'https://rubygems.org'
|
|
3
3
|
gemspec
|
4
4
|
|
5
5
|
gem 'bogus', '~> 0.1'
|
6
|
-
gem '
|
6
|
+
gem 'inflecto', '~> 0.0.2'
|
7
|
+
gem 'rspec', '~> 3.1'
|
7
8
|
|
8
|
-
group :test
|
9
|
-
|
10
|
-
|
9
|
+
gem "codeclimate-test-reporter", group: :test, require: false
|
10
|
+
|
11
|
+
group :tools do
|
12
|
+
gem 'guard'
|
13
|
+
gem 'guard-rspec'
|
11
14
|
|
12
|
-
|
15
|
+
gem 'rubocop'
|
16
|
+
|
17
|
+
platform :mri do
|
18
|
+
gem 'mutant'
|
19
|
+
gem 'mutant-rspec'
|
20
|
+
end
|
21
|
+
end
|
data/README.md
CHANGED
@@ -1,27 +1,35 @@
|
|
1
|
-
Virtus
|
2
|
-
======
|
3
|
-
|
4
|
-
[][gem]
|
5
|
-
[][travis]
|
6
|
-
[][gemnasium]
|
7
|
-
[][codeclimate]
|
8
|
-
[][coveralls]
|
9
|
-
[][inchpages]
|
10
|
-
|
11
1
|
[gem]: https://rubygems.org/gems/virtus
|
12
2
|
[travis]: https://travis-ci.org/solnic/virtus
|
13
3
|
[gemnasium]: https://gemnasium.com/solnic/virtus
|
14
4
|
[codeclimate]: https://codeclimate.com/github/solnic/virtus
|
15
5
|
[coveralls]: https://coveralls.io/r/solnic/virtus
|
16
|
-
[inchpages]: http://inch-ci.org/github/solnic/virtus
|
6
|
+
[inchpages]: http://inch-ci.org/github/solnic/virtus/
|
7
|
+
|
8
|
+
Virtus
|
9
|
+
======
|
10
|
+
|
11
|
+
# Ruby Object Mapper
|
12
|
+
|
13
|
+
[][gem]
|
14
|
+
[][travis]
|
15
|
+
[][gemnasium]
|
16
|
+
[][codeclimate]
|
17
|
+
[][codeclimate]
|
18
|
+
[][inchpages]
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
20
|
+
Virtus allows you to define attributes on classes, modules or class instances with
|
21
|
+
optional information about types, reader/writer method visibility and coercion
|
22
|
+
behavior. It supports a lot of coercions and advanced mapping of embedded objects
|
23
|
+
and collections.
|
24
|
+
|
25
|
+
You can use it in many different contexts like:
|
26
|
+
|
27
|
+
* Input parameter sanitization and coercion in web applications
|
28
|
+
* Mapping JSON to domain objects
|
29
|
+
* Encapsulating data-access in Value Objects
|
30
|
+
* Domain model prototyping
|
31
|
+
|
32
|
+
And probably more.
|
25
33
|
|
26
34
|
Installation
|
27
35
|
------------
|
@@ -181,6 +189,19 @@ page.reset_attribute(:views) # => 0
|
|
181
189
|
page.views # => 0
|
182
190
|
```
|
183
191
|
|
192
|
+
### Default values on dynamically extended instances
|
193
|
+
|
194
|
+
This requires you to set `:lazy` option because default values are set in the
|
195
|
+
constructor if it's set to false (which is the default setting):
|
196
|
+
|
197
|
+
``` ruby
|
198
|
+
User = Class.new
|
199
|
+
user = User.new
|
200
|
+
user.extend(Virtus.model)
|
201
|
+
user.attribute :name, String, default: 'jane', lazy: true
|
202
|
+
user.name # => "jane"
|
203
|
+
```
|
204
|
+
|
184
205
|
### Embedded Value
|
185
206
|
|
186
207
|
``` ruby
|
@@ -409,7 +430,7 @@ user.info.class # => Hash
|
|
409
430
|
# With a custom attribute encapsulating coercion-specific configuration
|
410
431
|
class NoisyString < Virtus::Attribute
|
411
432
|
def coerce(value)
|
412
|
-
|
433
|
+
value.to_s.upcase
|
413
434
|
end
|
414
435
|
end
|
415
436
|
|
data/Rakefile
CHANGED
@@ -1,5 +1,15 @@
|
|
1
|
-
|
1
|
+
require "rspec/core/rake_task"
|
2
2
|
|
3
|
-
|
3
|
+
RSpec::Core::RakeTask.new(:spec)
|
4
|
+
task default: [:spec]
|
4
5
|
|
5
|
-
|
6
|
+
begin
|
7
|
+
require "rubocop/rake_task"
|
8
|
+
|
9
|
+
Rake::Task[:default].enhance [:rubocop]
|
10
|
+
|
11
|
+
RuboCop::RakeTask.new do |task|
|
12
|
+
task.options << "--display-cop-names"
|
13
|
+
end
|
14
|
+
rescue LoadError
|
15
|
+
end
|
data/lib/virtus/configuration.rb
CHANGED
@@ -12,6 +12,9 @@ module Virtus
|
|
12
12
|
# Access the strict setting for this instance
|
13
13
|
attr_accessor :strict
|
14
14
|
|
15
|
+
# Access the required setting for this instance
|
16
|
+
attr_accessor :required
|
17
|
+
|
15
18
|
# Access the constructor setting for this instance
|
16
19
|
attr_accessor :constructor
|
17
20
|
|
@@ -24,11 +27,12 @@ module Virtus
|
|
24
27
|
#
|
25
28
|
# @api private
|
26
29
|
def initialize(options={})
|
27
|
-
@finalize = options.fetch(:finalize,true)
|
28
|
-
@coerce = options.fetch(:coerce,true)
|
29
|
-
@strict = options.fetch(:strict,false)
|
30
|
-
@
|
31
|
-
@
|
30
|
+
@finalize = options.fetch(:finalize, true)
|
31
|
+
@coerce = options.fetch(:coerce, true)
|
32
|
+
@strict = options.fetch(:strict, false)
|
33
|
+
@required = options.fetch(:required, true)
|
34
|
+
@constructor = options.fetch(:constructor, true)
|
35
|
+
@mass_assignment = options.fetch(:mass_assignment, true)
|
32
36
|
@coercer = Coercible::Coercer.new
|
33
37
|
|
34
38
|
yield self if block_given?
|
@@ -55,6 +59,7 @@ module Virtus
|
|
55
59
|
{ :coerce => coerce,
|
56
60
|
:finalize => finalize,
|
57
61
|
:strict => strict,
|
62
|
+
:required => required,
|
58
63
|
:configured_coercer => coercer }.freeze
|
59
64
|
end
|
60
65
|
|
data/lib/virtus/version.rb
CHANGED
@@ -25,10 +25,10 @@ class User
|
|
25
25
|
end
|
26
26
|
|
27
27
|
describe User do
|
28
|
-
it {
|
29
|
-
it {
|
30
|
-
it {
|
31
|
-
it {
|
28
|
+
it { is_expected.to respond_to(:phone_numbers) }
|
29
|
+
it { is_expected.to respond_to(:phone_numbers=) }
|
30
|
+
it { is_expected.to respond_to(:addresses) }
|
31
|
+
it { is_expected.to respond_to(:addresses=) }
|
32
32
|
|
33
33
|
let(:instance) do
|
34
34
|
described_class.new(:phone_numbers => phone_numbers_attributes,
|
@@ -48,28 +48,49 @@ describe User do
|
|
48
48
|
describe 'first entry' do
|
49
49
|
subject { instance.phone_numbers.first }
|
50
50
|
|
51
|
-
it {
|
51
|
+
it { is_expected.to be_instance_of(PhoneNumber) }
|
52
52
|
|
53
|
-
|
53
|
+
describe '#number' do
|
54
|
+
subject { super().number }
|
55
|
+
it { is_expected.to eql('212-555-1212') }
|
56
|
+
end
|
54
57
|
end
|
55
58
|
|
56
59
|
describe 'last entry' do
|
57
60
|
subject { instance.phone_numbers.last }
|
58
61
|
|
59
|
-
it {
|
62
|
+
it { is_expected.to be_instance_of(PhoneNumber) }
|
60
63
|
|
61
|
-
|
64
|
+
describe '#number' do
|
65
|
+
subject { super().number }
|
66
|
+
it { is_expected.to eql('919-444-3265') }
|
67
|
+
end
|
62
68
|
end
|
63
69
|
end
|
64
70
|
|
65
71
|
describe '#addresses' do
|
66
72
|
subject { instance.addresses.first }
|
67
73
|
|
68
|
-
it {
|
74
|
+
it { is_expected.to be_instance_of(Address) }
|
69
75
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
76
|
+
describe '#address' do
|
77
|
+
subject { super().address }
|
78
|
+
it { is_expected.to eql('1234 Any St.') }
|
79
|
+
end
|
80
|
+
|
81
|
+
describe '#locality' do
|
82
|
+
subject { super().locality }
|
83
|
+
it { is_expected.to eql('Anytown') }
|
84
|
+
end
|
85
|
+
|
86
|
+
describe '#region' do
|
87
|
+
subject { super().region }
|
88
|
+
it { is_expected.to eql('DC') }
|
89
|
+
end
|
90
|
+
|
91
|
+
describe '#postal_code' do
|
92
|
+
subject { super().postal_code }
|
93
|
+
it { is_expected.to eql('21234') }
|
94
|
+
end
|
74
95
|
end
|
75
96
|
end
|
@@ -26,9 +26,9 @@ describe Package do
|
|
26
26
|
it 'has 3 keys' do
|
27
27
|
expect(subject.keys.size).to eq(3)
|
28
28
|
end
|
29
|
-
it {
|
30
|
-
it {
|
31
|
-
it {
|
29
|
+
it { is_expected.to have_key :width }
|
30
|
+
it { is_expected.to have_key :height }
|
31
|
+
it { is_expected.to have_key :length }
|
32
32
|
|
33
33
|
it 'should be coerced to [Symbol => Float] format' do
|
34
34
|
expect(dimensions[:width]).to be_eql(2.2)
|
@@ -43,8 +43,8 @@ describe Package do
|
|
43
43
|
it 'has 2 keys' do
|
44
44
|
expect(subject.keys.size).to eq(2)
|
45
45
|
end
|
46
|
-
it {
|
47
|
-
it {
|
46
|
+
it { is_expected.to have_key 'from' }
|
47
|
+
it { is_expected.to have_key 'to' }
|
48
48
|
|
49
49
|
it 'should be coerced to [String => String] format' do
|
50
50
|
expect(meta_info['from']).to eq('Me')
|
@@ -20,7 +20,7 @@ shared_examples_for 'a #freeze method' do
|
|
20
20
|
it_should_behave_like 'an idempotent method'
|
21
21
|
|
22
22
|
it 'returns object' do
|
23
|
-
|
23
|
+
is_expected.to be(object)
|
24
24
|
end
|
25
25
|
|
26
26
|
it 'prevents future modifications' do
|
@@ -29,7 +29,10 @@ shared_examples_for 'a #freeze method' do
|
|
29
29
|
expect { object.instance_variable_set(:@foo, :bar) }.to(expectation)
|
30
30
|
end
|
31
31
|
|
32
|
-
|
32
|
+
describe '#frozen?' do
|
33
|
+
subject { super().frozen? }
|
34
|
+
it { is_expected.to be(true) }
|
35
|
+
end
|
33
36
|
|
34
37
|
it 'allows to access attribute' do
|
35
38
|
expect(subject.name).to eql('John')
|
@@ -2,15 +2,15 @@ shared_examples_for 'an options class method' do
|
|
2
2
|
context 'with no argument' do
|
3
3
|
subject { object.send(method) }
|
4
4
|
|
5
|
-
it {
|
5
|
+
it { is_expected.to be(default) }
|
6
6
|
end
|
7
7
|
|
8
8
|
context 'with a default value' do
|
9
9
|
subject { object.send(method, value) }
|
10
10
|
|
11
|
-
let(:value) {
|
11
|
+
let(:value) { mock('value') }
|
12
12
|
|
13
|
-
it {
|
13
|
+
it { is_expected.to equal(object) }
|
14
14
|
|
15
15
|
it 'sets the default value for the class method' do
|
16
16
|
expect { subject }.to change { object.send(method) }.from(default).to(value)
|
data/spec/spec_helper.rb
CHANGED
@@ -1,22 +1,9 @@
|
|
1
|
-
if
|
2
|
-
require
|
3
|
-
|
4
|
-
|
5
|
-
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
6
|
-
SimpleCov::Formatter::HTMLFormatter,
|
7
|
-
Coveralls::SimpleCov::Formatter
|
8
|
-
]
|
9
|
-
|
10
|
-
SimpleCov.start do
|
11
|
-
command_name 'spec:unit'
|
12
|
-
add_filter 'config/'
|
13
|
-
add_filter 'spec'
|
14
|
-
add_filter '.bundle'
|
15
|
-
end
|
1
|
+
if RUBY_ENGINE == "rbx"
|
2
|
+
require "codeclimate-test-reporter"
|
3
|
+
CodeClimate::TestReporter.start
|
16
4
|
end
|
17
5
|
|
18
6
|
require 'rspec'
|
19
|
-
require 'rspec/its'
|
20
7
|
require 'bogus/rspec'
|
21
8
|
require 'virtus'
|
22
9
|
require 'inflecto' # for resolving namespaced constant names
|
@@ -33,7 +20,6 @@ ENV['TZ'] = 'UTC'
|
|
33
20
|
Dir[File.expand_path('../shared/**/*.rb', __FILE__)].each { |file| require file }
|
34
21
|
|
35
22
|
RSpec.configure do |config|
|
36
|
-
|
37
23
|
# Remove anonymous- and example- Attribute classes from Attribute descendants
|
38
24
|
config.after :all do
|
39
25
|
stack = [ Virtus::Attribute ]
|
@@ -53,5 +39,4 @@ RSpec.configure do |config|
|
|
53
39
|
end
|
54
40
|
end
|
55
41
|
end
|
56
|
-
|
57
42
|
end
|
@@ -10,13 +10,13 @@ describe Virtus::Attribute::Boolean, '#coerce' do
|
|
10
10
|
context 'with a truthy value' do
|
11
11
|
let(:input) { 1 }
|
12
12
|
|
13
|
-
it {
|
13
|
+
it { is_expected.to be(true) }
|
14
14
|
end
|
15
15
|
|
16
16
|
context 'with a falsy value' do
|
17
17
|
let(:input) { 0 }
|
18
18
|
|
19
|
-
it {
|
19
|
+
it { is_expected.to be(false) }
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -26,7 +26,7 @@ describe Virtus::Attribute::Boolean, '#coerce' do
|
|
26
26
|
context 'with a coercible input' do
|
27
27
|
let(:input) { 1 }
|
28
28
|
|
29
|
-
it {
|
29
|
+
it { is_expected.to be(true) }
|
30
30
|
end
|
31
31
|
|
32
32
|
context 'with a non-coercible input' do
|
@@ -8,18 +8,18 @@ describe Virtus::Attribute::Boolean, '#value_coerced?' do
|
|
8
8
|
context 'when input is true' do
|
9
9
|
let(:input) { true }
|
10
10
|
|
11
|
-
it {
|
11
|
+
it { is_expected.to be(true) }
|
12
12
|
end
|
13
13
|
|
14
14
|
context 'when input is false' do
|
15
15
|
let(:input) { false }
|
16
16
|
|
17
|
-
it {
|
17
|
+
it { is_expected.to be(true) }
|
18
18
|
end
|
19
19
|
|
20
20
|
context 'when input is not coerced' do
|
21
21
|
let(:input) { 1 }
|
22
22
|
|
23
|
-
it {
|
23
|
+
it { is_expected.to be(false) }
|
24
24
|
end
|
25
25
|
end
|