modelish 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +1 -0
- data/CHANGELOG.md +10 -2
- data/README.md +66 -21
- data/Rakefile +1 -1
- data/lib/modelish.rb +2 -1
- data/lib/modelish/base.rb +20 -6
- data/lib/modelish/configuration.rb +50 -0
- data/lib/modelish/version.rb +1 -1
- data/modelish.gemspec +0 -1
- data/spec/modelish/base_spec.rb +39 -0
- data/spec/modelish/configuration_spec.rb +111 -0
- data/spec/support/unknown_property_examples.rb +19 -0
- metadata +10 -18
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--no-private --markup markdown lib/**/*.rb - CHANGELOG.md LICENSE
|
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,17 @@
|
|
1
|
-
|
1
|
+
# CHANGELOG
|
2
|
+
|
3
|
+
## 0.1.3 (2011-10-25)
|
4
|
+
|
5
|
+
* Added configuration option to ignore unknown properties. The default behavior continues
|
6
|
+
to be raising an error when an unknown property name is encountered in an initialization
|
7
|
+
hash.
|
8
|
+
|
9
|
+
## 0.1.2 (2011-03-31)
|
2
10
|
|
3
11
|
* Fixed SystemStackError when a typed property with the same name is defined multiple times.
|
4
12
|
* Use explicit path when loading modelish classes.
|
5
13
|
|
6
|
-
##
|
14
|
+
## 0.1.1 (2011-03-28)
|
7
15
|
|
8
16
|
* Add DateTime to standard supported property types.
|
9
17
|
|
data/README.md
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
When a real modeling framework is too heavy, sometimes you want something just
|
4
4
|
a little modelish.
|
5
5
|
|
6
|
+
## Overview ##
|
7
|
+
|
6
8
|
If a Hash or OpenStruct almost suits your needs, but you need bits of
|
7
9
|
model-like behavior such as simple validation and typed values, modelish can
|
8
10
|
help.
|
@@ -10,18 +12,20 @@ help.
|
|
10
12
|
If you need persistence or anything but the most basic functionality, modelish
|
11
13
|
will frustrate you to no end.
|
12
14
|
|
13
|
-
##
|
15
|
+
## Documentation ##
|
14
16
|
|
15
|
-
|
17
|
+
See the [rdocs][docs].
|
16
18
|
|
17
|
-
|
19
|
+
## Installation ##
|
18
20
|
|
19
|
-
|
21
|
+
modelish is available on [Rubygems][rubygems] and can be installed via:
|
20
22
|
|
21
|
-
|
23
|
+
$ gem install modelish
|
22
24
|
|
23
25
|
## Basics ##
|
24
26
|
|
27
|
+
### Property Types ###
|
28
|
+
|
25
29
|
The modelish syntax is very similar to some of the classes provided by
|
26
30
|
[hashie]. In fact, the initial implementation simply extended
|
27
31
|
[Hashie::Trash][trash] to add property types:
|
@@ -44,21 +48,23 @@ key-mappings:
|
|
44
48
|
:my_simple_property => 'bar')
|
45
49
|
|
46
50
|
f.my_date
|
47
|
-
|
51
|
+
# => #<Date: 2011-03-10 (4911261/2,0,2299161)>
|
48
52
|
f.my_float
|
49
|
-
|
53
|
+
# => 0.0
|
50
54
|
f.my_funky_id
|
51
|
-
|
55
|
+
# => 42
|
52
56
|
f.my_simple_property
|
53
|
-
|
57
|
+
# => "bar"
|
58
|
+
|
59
|
+
### Property Validation ###
|
54
60
|
|
55
61
|
modelish also supports defining simple property validations:
|
56
62
|
|
57
63
|
class Bar < Modelish::Base
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
64
|
+
property :important_field, :required => true
|
65
|
+
property :state, :max_length => 2
|
66
|
+
property :my_int, :type => Integer, :validate_type => true
|
67
|
+
property :another_field, :validator => lambda { |val| "val must respond to []" unless val.respond_to?(:[]) }
|
62
68
|
end
|
63
69
|
|
64
70
|
Validations can be run using methods that return an error map (keyed on property name), raise errors, or return a boolean value to indicate validation outcome.
|
@@ -68,28 +74,67 @@ Validations can be run using methods that return an error map (keyed on property
|
|
68
74
|
:my_int => 42,
|
69
75
|
:another_field => Hash.new)
|
70
76
|
valid_bar.valid?
|
71
|
-
|
77
|
+
# => true
|
72
78
|
|
73
79
|
valid_bar.validate
|
74
|
-
|
80
|
+
# => {}
|
75
81
|
|
76
82
|
valid_bar.validate!
|
77
|
-
|
83
|
+
# => nil
|
78
84
|
|
79
85
|
|
80
86
|
invalid_bar = Bar.new(:state => 'a value that is too long',
|
81
87
|
:my_int => 'this is not an integer',
|
82
88
|
:another_field => Object.new)
|
83
89
|
invalid_bar.valid?
|
84
|
-
|
90
|
+
# => false
|
85
91
|
|
86
92
|
invalid_bar.validate
|
87
|
-
|
93
|
+
# => {:important_field=>[#<ArgumentError: important_field must not be nil or blank>],
|
94
|
+
# :my_int=>[#<ArgumentError: my_int must be of type Integer, but got "this is not an integer">],
|
95
|
+
# :another_field=>[#<ArgumentError: val must respond to []>],
|
96
|
+
# :state=>[#<ArgumentError: state must be less than 2 characters>]}
|
88
97
|
|
89
98
|
invalid_bar.validate!
|
90
|
-
|
91
|
-
|
92
|
-
|
99
|
+
# ArgumentError: important_field must not be nil or blank
|
100
|
+
|
101
|
+
## Configuration ##
|
102
|
+
|
103
|
+
By default, modelish will raise an error when it encounters unknown property names in an initialization hash. If you'd prefer modelish to ignore unknown properties, you can override this default behavior for all of your modelish models:
|
104
|
+
|
105
|
+
require 'modelish'
|
106
|
+
|
107
|
+
Modelish.configure do |config|
|
108
|
+
config.ignore_unknown_properties = true
|
109
|
+
end
|
110
|
+
|
111
|
+
class MyModel < Modelish::Base
|
112
|
+
property :foo
|
113
|
+
end
|
114
|
+
|
115
|
+
m = MyModel.new(:foo => 'value', :bar => true)
|
116
|
+
# => <#MyModel foo="value">
|
117
|
+
|
118
|
+
Or you can selectively enable the setting for a particular model:
|
119
|
+
|
120
|
+
require 'modelish'
|
121
|
+
|
122
|
+
class MyPermissiveModel < Modelish::Base
|
123
|
+
property :foo
|
124
|
+
ignore_unknown_properties!
|
125
|
+
end
|
126
|
+
|
127
|
+
class MyStrictModel < Modelish::Base
|
128
|
+
property :foo
|
129
|
+
end
|
130
|
+
|
131
|
+
p = MyPermissiveModel.new(:foo => 'value', :bar => true)
|
132
|
+
# => <#MyPermissiveModel foo="value">
|
133
|
+
|
134
|
+
s = MyStrictModel.new(:foo => 'value', :bar => true)
|
135
|
+
# NoMethodError: The property 'bar' is not defined for this Modelish object
|
93
136
|
|
94
137
|
[hashie]: https://github.com/intridea/hashie
|
95
138
|
[trash]: http://rdoc.info/github/intridea/hashie/master/Hashie/Trash
|
139
|
+
[rubygems]: https://rubygems.org/gems/modelish
|
140
|
+
[docs]: http://rubydoc.info/gems/modelish
|
data/Rakefile
CHANGED
@@ -9,7 +9,7 @@ task :default => :spec
|
|
9
9
|
namespace :doc do
|
10
10
|
require 'yard'
|
11
11
|
YARD::Rake::YardocTask.new do |task|
|
12
|
-
task.files = ['README.md', 'lib/**/*.rb']
|
12
|
+
task.files = ['README.md', 'CHANGELOG.md', 'LICENSE', 'lib/**/*.rb']
|
13
13
|
task.options = [
|
14
14
|
'--markup', 'markdown',
|
15
15
|
]
|
data/lib/modelish.rb
CHANGED
data/lib/modelish/base.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
require 'hashie'
|
2
|
-
require 'property_types'
|
3
|
-
require 'validations'
|
2
|
+
require 'modelish/property_types'
|
3
|
+
require 'modelish/validations'
|
4
|
+
require 'modelish/configuration'
|
4
5
|
|
5
6
|
module Modelish
|
6
7
|
class Base < Hashie::Trash
|
7
8
|
include PropertyTypes
|
8
9
|
include Validations
|
10
|
+
extend Configuration
|
9
11
|
|
10
12
|
# Creates a new attribute.
|
11
13
|
#
|
@@ -19,14 +21,14 @@ module Modelish
|
|
19
21
|
# @option opts [Class,Proc] :type the type of the property value. For
|
20
22
|
# a list of accepted types, see
|
21
23
|
# {Modelish::PropertyTypes}
|
22
|
-
# @
|
24
|
+
# @option opts [true,false] :required enables validation for the property
|
23
25
|
# value's presence; nil or blank values
|
24
26
|
# will cause validation methods to fail
|
25
|
-
# @
|
27
|
+
# @option opts [Integer] :max_length the maximum allowable length for a valid
|
26
28
|
# property value
|
27
|
-
# @
|
29
|
+
# @option opts [true,false] :validate_type enables validation for the property value's
|
28
30
|
# type based on the :type option
|
29
|
-
# @
|
31
|
+
# @option opts [Proc] :validator A block that accepts a value and validates it;
|
30
32
|
# should return nil if validation passes, or an error
|
31
33
|
# message or error object if validation fails.
|
32
34
|
# See {Modelish::Validations}
|
@@ -40,5 +42,17 @@ module Modelish
|
|
40
42
|
add_validator(name, &options[:validator]) if options[:validator]
|
41
43
|
add_validator(name) { |val| validate_type(name, val, options[:type]) } if options[:validate_type]
|
42
44
|
end
|
45
|
+
|
46
|
+
private
|
47
|
+
def property_exists?(property)
|
48
|
+
if self.class.property?(property.to_sym)
|
49
|
+
true
|
50
|
+
elsif self.class.ignore_unknown_properties ||
|
51
|
+
(self.class.ignore_unknown_properties.nil? && Modelish.ignore_unknown_properties)
|
52
|
+
false
|
53
|
+
else
|
54
|
+
raise NoMethodError, "The property '#{property}' is not defined for this Modelish object."
|
55
|
+
end
|
56
|
+
end
|
43
57
|
end
|
44
58
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Modelish
|
2
|
+
module Configuration
|
3
|
+
# If true, ignore unknown property names when initializing new models;
|
4
|
+
# otherwise, raise an error when an unknown property is encountered.
|
5
|
+
# Defaults to false.
|
6
|
+
attr_accessor :ignore_unknown_properties
|
7
|
+
|
8
|
+
# When set, unknown property names will be ignored during modelish initialization
|
9
|
+
# and property setting.
|
10
|
+
#
|
11
|
+
# @see {raise_errors_on_unknown_properties!}
|
12
|
+
def ignore_unknown_properties!
|
13
|
+
self.ignore_unknown_properties = true
|
14
|
+
end
|
15
|
+
|
16
|
+
# When set, unknown property names will cause errors to be raised when encountered
|
17
|
+
# during modelish initialization and property setting. This is the default behavior.
|
18
|
+
#
|
19
|
+
# @see {ignore_unknown_properties!}
|
20
|
+
def raise_errors_on_unknown_properties!
|
21
|
+
self.ignore_unknown_properties = false
|
22
|
+
end
|
23
|
+
|
24
|
+
# When this module is extended, set all configuration options to their default values
|
25
|
+
def self.extended(base)
|
26
|
+
base.reset
|
27
|
+
end
|
28
|
+
|
29
|
+
# Configures this module through the given +block+.
|
30
|
+
# Default configuration options will be applied unless
|
31
|
+
# they are explicitly overridden in the +block+.
|
32
|
+
#
|
33
|
+
# @example Disable raising errors on unknown property names
|
34
|
+
# Modelish.configure do |config|
|
35
|
+
# config.ignore_unknown_properties = true
|
36
|
+
# end
|
37
|
+
def configure
|
38
|
+
if block_given?
|
39
|
+
yield self
|
40
|
+
end
|
41
|
+
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
# Resets this module's configuration.
|
46
|
+
def reset
|
47
|
+
self.ignore_unknown_properties = false
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/modelish/version.rb
CHANGED
data/modelish.gemspec
CHANGED
data/spec/modelish/base_spec.rb
CHANGED
@@ -10,6 +10,45 @@ describe Modelish::Base do
|
|
10
10
|
|
11
11
|
it { should respond_to(:property) }
|
12
12
|
|
13
|
+
context 'without any properties' do
|
14
|
+
subject { model }
|
15
|
+
|
16
|
+
context 'when the model is initialized with an unknown property' do
|
17
|
+
let(:init_options) { {unknown_prop => 'whatever'} }
|
18
|
+
let(:unknown_prop) { :foo }
|
19
|
+
|
20
|
+
context 'when ignore_unknown_properties is configured at the class level' do
|
21
|
+
before { model_class.ignore_unknown_properties = ignore_unknown_props }
|
22
|
+
after { model_class.reset }
|
23
|
+
|
24
|
+
it_should_behave_like 'an unknown property handler'
|
25
|
+
end
|
26
|
+
|
27
|
+
context "when ignore_unknown_properties is configured globally" do
|
28
|
+
before { Modelish.configure { |c| c.ignore_unknown_properties = ignore_unknown_props } }
|
29
|
+
after { Modelish.reset }
|
30
|
+
|
31
|
+
it_should_behave_like 'an unknown property handler'
|
32
|
+
|
33
|
+
context 'when ignore_unknown_properties is configured differently at the class level' do
|
34
|
+
before { Modelish.configure { |c| c.ignore_unknown_properties = !ignore_unknown_props } }
|
35
|
+
after { Modelish.reset }
|
36
|
+
|
37
|
+
before { model_class.ignore_unknown_properties = ignore_unknown_props }
|
38
|
+
after { model_class.reset }
|
39
|
+
|
40
|
+
it_should_behave_like 'an unknown property handler'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'when ignore_unknown_properties has not been configured' do
|
45
|
+
it 'should raise an error' do
|
46
|
+
expect { subject }.to raise_error(NoMethodError)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
13
52
|
context "with simple property" do
|
14
53
|
before { model_class.property(property_name) }
|
15
54
|
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Modelish::Configuration do
|
4
|
+
let(:test_module) do
|
5
|
+
module TestModule
|
6
|
+
extend Modelish::Configuration
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
subject { test_module }
|
11
|
+
|
12
|
+
after { test_module.reset }
|
13
|
+
|
14
|
+
it { should respond_to(:configure) }
|
15
|
+
|
16
|
+
context 'with default configuration' do
|
17
|
+
its(:ignore_unknown_properties) { should be_false }
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '.configure' do
|
21
|
+
subject { test_module.configure(&config_block) }
|
22
|
+
|
23
|
+
context 'with full configuration' do
|
24
|
+
let(:config_block) do
|
25
|
+
lambda do |config|
|
26
|
+
config.ignore_unknown_properties = ignore_unknown_props
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when ignore_unknown_properties is true' do
|
31
|
+
let(:ignore_unknown_props) { true }
|
32
|
+
its(:ignore_unknown_properties) { should be_true }
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'when ignore_unknown_properties is false' do
|
36
|
+
let(:ignore_unknown_props) { false }
|
37
|
+
its(:ignore_unknown_properties) { should be_false }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '.reset' do
|
43
|
+
subject { test_module.reset }
|
44
|
+
|
45
|
+
before { test_module.configure { |c| c.ignore_unknown_properties = true } }
|
46
|
+
|
47
|
+
it 'should reset the value of ignore_unknown_properties' do
|
48
|
+
expect { subject }.to change { test_module.ignore_unknown_properties }.from(true).to(false)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe 'ignore_unknown_properties!' do
|
53
|
+
before { test_module.ignore_unknown_properties = ignore_unknown_props }
|
54
|
+
|
55
|
+
subject { test_module.ignore_unknown_properties! }
|
56
|
+
|
57
|
+
context 'when ignore_unknown_properties is true' do
|
58
|
+
let(:ignore_unknown_props) { true }
|
59
|
+
|
60
|
+
it 'should not change the setting' do
|
61
|
+
expect { subject }.to_not change { test_module.ignore_unknown_properties }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'when ignore_unknown_properties is false' do
|
66
|
+
let(:ignore_unknown_props) { false }
|
67
|
+
|
68
|
+
it 'should change the setting' do
|
69
|
+
expect { subject }.to change { test_module.ignore_unknown_properties }.from(false).to(true)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'when ignore_unknown_properties is nil' do
|
74
|
+
let(:ignore_unknown_props) { nil }
|
75
|
+
|
76
|
+
it 'should change the setting' do
|
77
|
+
expect { subject }.to change { test_module.ignore_unknown_properties }.from(nil).to(true)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe 'raise_errors_on_unknown_properties!' do
|
83
|
+
before { test_module.ignore_unknown_properties = ignore_unknown_props }
|
84
|
+
|
85
|
+
subject { test_module.raise_errors_on_unknown_properties! }
|
86
|
+
|
87
|
+
context 'when ignore_unknown_properties is true' do
|
88
|
+
let(:ignore_unknown_props) { true }
|
89
|
+
|
90
|
+
it 'should change the setting' do
|
91
|
+
expect { subject }.to change { test_module.ignore_unknown_properties }.from(true).to(false)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'when ignore_unknown_properties is false' do
|
96
|
+
let(:ignore_unknown_props) { false }
|
97
|
+
|
98
|
+
it 'should not change the setting' do
|
99
|
+
expect { subject }.to_not change { test_module.ignore_unknown_properties }
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'when ignore_unknown_properties is nil' do
|
104
|
+
let(:ignore_unknown_props) { nil }
|
105
|
+
|
106
|
+
it 'should change the setting' do
|
107
|
+
expect { subject }.to change { test_module.ignore_unknown_properties }.from(nil).to(false)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
shared_examples_for 'an unknown property handler' do
|
2
|
+
context 'when ignore_unknown_properties is set to false' do
|
3
|
+
let(:ignore_unknown_props) { false }
|
4
|
+
|
5
|
+
it 'should raise an error' do
|
6
|
+
expect { subject }.to raise_error(NoMethodError)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'when ignore_unknown_properties is set to true' do
|
11
|
+
let(:ignore_unknown_props) { true }
|
12
|
+
|
13
|
+
it 'should not raise an error' do
|
14
|
+
expect { subject }.to_not raise_error
|
15
|
+
end
|
16
|
+
|
17
|
+
it { should_not respond_to(unknown_prop) }
|
18
|
+
end
|
19
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: modelish
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 29
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 3
|
10
|
+
version: 0.1.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Maeve Revels
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-10-25 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -79,20 +79,6 @@ dependencies:
|
|
79
79
|
version: 2.0.11
|
80
80
|
type: :development
|
81
81
|
version_requirements: *id004
|
82
|
-
- !ruby/object:Gem::Dependency
|
83
|
-
name: autotest
|
84
|
-
prerelease: false
|
85
|
-
requirement: &id005 !ruby/object:Gem::Requirement
|
86
|
-
none: false
|
87
|
-
requirements:
|
88
|
-
- - ">="
|
89
|
-
- !ruby/object:Gem::Version
|
90
|
-
hash: 3
|
91
|
-
segments:
|
92
|
-
- 0
|
93
|
-
version: "0"
|
94
|
-
type: :development
|
95
|
-
version_requirements: *id005
|
96
82
|
description: Sometimes you need something just a little modelish.
|
97
83
|
email:
|
98
84
|
- maeve.revels@g5platform.com
|
@@ -106,6 +92,7 @@ files:
|
|
106
92
|
- .gitignore
|
107
93
|
- .rspec
|
108
94
|
- .rvmrc
|
95
|
+
- .yardopts
|
109
96
|
- CHANGELOG.md
|
110
97
|
- Gemfile
|
111
98
|
- LICENSE
|
@@ -113,17 +100,20 @@ files:
|
|
113
100
|
- Rakefile
|
114
101
|
- lib/modelish.rb
|
115
102
|
- lib/modelish/base.rb
|
103
|
+
- lib/modelish/configuration.rb
|
116
104
|
- lib/modelish/property_types.rb
|
117
105
|
- lib/modelish/validations.rb
|
118
106
|
- lib/modelish/version.rb
|
119
107
|
- modelish.gemspec
|
120
108
|
- spec/modelish/base_spec.rb
|
109
|
+
- spec/modelish/configuration_spec.rb
|
121
110
|
- spec/modelish/property_types_spec.rb
|
122
111
|
- spec/modelish/validations_spec.rb
|
123
112
|
- spec/modelish_spec.rb
|
124
113
|
- spec/spec_helper.rb
|
125
114
|
- spec/support/property_examples.rb
|
126
115
|
- spec/support/typed_property_examples.rb
|
116
|
+
- spec/support/unknown_property_examples.rb
|
127
117
|
- spec/support/validation_examples.rb
|
128
118
|
has_rdoc: true
|
129
119
|
homepage: http://github.com/maeve/modelish
|
@@ -161,10 +151,12 @@ specification_version: 3
|
|
161
151
|
summary: A lightweight pseudo-modeling not-quite-framework
|
162
152
|
test_files:
|
163
153
|
- spec/modelish/base_spec.rb
|
154
|
+
- spec/modelish/configuration_spec.rb
|
164
155
|
- spec/modelish/property_types_spec.rb
|
165
156
|
- spec/modelish/validations_spec.rb
|
166
157
|
- spec/modelish_spec.rb
|
167
158
|
- spec/spec_helper.rb
|
168
159
|
- spec/support/property_examples.rb
|
169
160
|
- spec/support/typed_property_examples.rb
|
161
|
+
- spec/support/unknown_property_examples.rb
|
170
162
|
- spec/support/validation_examples.rb
|