virtus 1.0.3 → 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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 Version](https://badge.fury.io/rb/virtus.png)][gem]
|
5
|
-
[![Build Status](https://secure.travis-ci.org/solnic/virtus.png?branch=master)][travis]
|
6
|
-
[![Dependency Status](https://gemnasium.com/solnic/virtus.png)][gemnasium]
|
7
|
-
[![Code Climate](https://codeclimate.com/github/solnic/virtus.png)][codeclimate]
|
8
|
-
[![Coverage Status](https://coveralls.io/repos/solnic/virtus/badge.png?branch=master)][coveralls]
|
9
|
-
[![Inline docs](http://inch-ci.org/github/solnic/virtus.png)][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 Version](https://badge.fury.io/rb/rom.svg)][gem]
|
14
|
+
[![Build Status](https://travis-ci.org/solnic/virtus.svg?branch=master)][travis]
|
15
|
+
[![Dependency Status](https://gemnasium.com/solnic/virtus.png)][gemnasium]
|
16
|
+
[![Code Climate](https://codeclimate.com/github/solnic/virtus/badges/gpa.svg)][codeclimate]
|
17
|
+
[![Test Coverage](https://codeclimate.com/github/solnic/virtus/badges/coverage.svg)][codeclimate]
|
18
|
+
[![Inline docs](http://inch-ci.org/github/solnic/virtus.svg?branch=master)][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
|