disposable 0.4.3 → 0.4.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 +23 -5
- data/CHANGES.md +4 -0
- data/Gemfile +5 -0
- data/README.md +2 -2
- data/disposable.gemspec +2 -2
- data/lib/disposable/rescheme.rb +1 -3
- data/lib/disposable/twin/coercion.rb +5 -2
- data/lib/disposable/twin/setup.rb +1 -1
- data/lib/disposable/twin/sync.rb +1 -1
- data/lib/disposable/version.rb +1 -1
- data/test/callback_group_test.rb +2 -3
- data/test/callbacks_test.rb +5 -5
- data/test/test_helper.rb +9 -6
- data/test/twin/changed_test.rb +1 -1
- data/test/twin/coercion_test.rb +18 -18
- data/test/twin/collection_test.rb +3 -3
- data/test/twin/hash_test.rb +57 -10
- data/test/twin/option_test.rb +1 -1
- data/test/twin/parent_test.rb +2 -2
- data/test/twin/property_processor_test.rb +2 -2
- data/test/twin/readable_test.rb +2 -2
- data/test/twin/save_test.rb +14 -14
- data/test/twin/struct/coercion_test.rb +36 -0
- data/test/twin/struct_test.rb +2 -2
- data/test/twin/sync_option_test.rb +2 -2
- data/test/twin/sync_test.rb +12 -12
- data/test/twin/twin_test.rb +2 -2
- data/test/twin/unnest_test.rb +2 -2
- data/test/twin/virtual_test.rb +1 -1
- metadata +13 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c909813e9e956a7fc7f01053b0be5984ccfb8ca9
|
4
|
+
data.tar.gz: dfa602431c42bb639e696eaf07e5822ad2f89e58
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8fdf6d50142307f1dad082e3ab73639888e1fe37c482fa49e3379d5751e39e83ba3d60e6f00699083d402f4ca56eb21be111ccbc069f2e0ee28f573838953d18
|
7
|
+
data.tar.gz: 99b5c357dbb03d0870ae9934732cc7786e37d728abdcfc6e7430b0cb6ba7de8fb47fd4d589edd501b14528bda26831fced5939814198e7e6906b397907f5bf93
|
data/.travis.yml
CHANGED
@@ -1,13 +1,31 @@
|
|
1
1
|
language: ruby
|
2
2
|
sudo: false
|
3
3
|
rvm:
|
4
|
-
-
|
5
|
-
- 2.
|
4
|
+
- ruby-head
|
5
|
+
- 2.5
|
6
|
+
- 2.4
|
7
|
+
- 2.3
|
6
8
|
- 2.2
|
7
|
-
|
8
|
-
|
9
|
+
env:
|
10
|
+
- "DRY_TYPES=0.13"
|
11
|
+
- "DRY_TYPES=0.12"
|
12
|
+
- "ACTIVERECORD=5.0"
|
13
|
+
- "ACTIVERECORD=5.1"
|
14
|
+
- "ACTIVERECORD=5.2"
|
9
15
|
gemfile:
|
10
16
|
- Gemfile
|
11
17
|
matrix:
|
18
|
+
fast_finish: true
|
19
|
+
include:
|
20
|
+
- { rvm: 2.3, env: ACTIVERECORD=4.2 }
|
21
|
+
- { rvm: 2.2, env: ACTIVERECORD=4.2 }
|
22
|
+
- { rvm: 2.3, env: ACTIVERECORD=4.1 }
|
23
|
+
- { rvm: 2.2, env: ACTIVERECORD=4.1 }
|
24
|
+
- rvm: 2.1
|
25
|
+
env:
|
26
|
+
- ACTIVERECORD=4.1
|
27
|
+
- DRY_TYPES=0.10
|
12
28
|
allow_failures:
|
13
|
-
- rvm:
|
29
|
+
- rvm: ruby-head
|
30
|
+
- env: ACTIVERECORD=4.1
|
31
|
+
- rvm: 2.1
|
data/CHANGES.md
CHANGED
data/Gemfile
CHANGED
@@ -8,6 +8,11 @@ gemspec
|
|
8
8
|
# gem "declarative", github: "apotonick/declarative"
|
9
9
|
gem "minitest-line"
|
10
10
|
|
11
|
+
{ "dry-types" => ENV['DRY_TYPES'], "activerecord" => ENV['ACTIVERECORD']}.each do |gem_name, dependency|
|
12
|
+
next if dependency.nil?
|
13
|
+
gem gem_name, dependency
|
14
|
+
end
|
15
|
+
|
11
16
|
# gem "dry-struct"
|
12
17
|
|
13
18
|
|
data/README.md
CHANGED
@@ -181,7 +181,7 @@ property :artist, twin: TwinArtist
|
|
181
181
|
|
182
182
|
## Unnest
|
183
183
|
|
184
|
-
#todo: document
|
184
|
+
# todo: document
|
185
185
|
|
186
186
|
## Features
|
187
187
|
|
@@ -206,7 +206,7 @@ class AlbumTwin < Disposable::Twin
|
|
206
206
|
feature Coercion
|
207
207
|
feature Setup::SkipSetter
|
208
208
|
|
209
|
-
property :id, type: Types::
|
209
|
+
property :id, type: Types::Params::Integer
|
210
210
|
```
|
211
211
|
|
212
212
|
The `:type` option defines the coercion type. You may incluce `Setup::SkipSetter`, too, as otherwise the coercion will happen at initialization time and in the setter.
|
data/disposable.gemspec
CHANGED
@@ -26,8 +26,8 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.add_development_dependency "bundler", "~> 1.3"
|
27
27
|
spec.add_development_dependency "rake"
|
28
28
|
spec.add_development_dependency "minitest"
|
29
|
-
spec.add_development_dependency "activerecord"
|
29
|
+
spec.add_development_dependency "activerecord"#, "4.2.5"
|
30
30
|
spec.add_development_dependency "sqlite3"
|
31
|
-
spec.add_development_dependency "dry-types"
|
31
|
+
spec.add_development_dependency "dry-types"# "~> 0.6"
|
32
32
|
# spec.add_development_dependency "database_cleaner"
|
33
33
|
end
|
data/lib/disposable/rescheme.rb
CHANGED
@@ -30,9 +30,7 @@ class Disposable::Rescheme
|
|
30
30
|
|
31
31
|
private
|
32
32
|
def build_representer(options)
|
33
|
-
Class.new(options[:superclass])
|
34
|
-
include *options[:include]
|
35
|
-
end
|
33
|
+
Class.new(options[:superclass]) { include(*options[:include]) }
|
36
34
|
end
|
37
35
|
|
38
36
|
def build_definition!(options, source_dfn, representer, &block)
|
@@ -5,6 +5,9 @@ module Disposable::Twin::Coercion
|
|
5
5
|
include Dry::Types.module
|
6
6
|
end
|
7
7
|
|
8
|
+
DRY_TYPES_VERSION = Integer(Dry::Types::VERSION.split('.')[-2])
|
9
|
+
DRY_TYPES_CONSTANT = DRY_TYPES_VERSION < 13 ? Types::Form : Types::Params
|
10
|
+
|
8
11
|
module ClassMethods
|
9
12
|
def property(name, options={}, &block)
|
10
13
|
super(name, options, &block).tap do
|
@@ -13,11 +16,11 @@ module Disposable::Twin::Coercion
|
|
13
16
|
end
|
14
17
|
|
15
18
|
def coercing_setter!(name, type, nilify=false)
|
16
|
-
type = type ? (
|
19
|
+
type = type ? (DRY_TYPES_CONSTANT::Nil | type) : DRY_TYPES_CONSTANT::Nil if nilify
|
17
20
|
|
18
21
|
mod = Module.new do
|
19
22
|
define_method("#{name}=") do |value|
|
20
|
-
super type.
|
23
|
+
super type.(value)
|
21
24
|
end
|
22
25
|
end
|
23
26
|
include mod
|
data/lib/disposable/twin/sync.rb
CHANGED
@@ -22,7 +22,7 @@ class Disposable::Twin
|
|
22
22
|
def self.hash_representer(twin_class, &block)
|
23
23
|
Disposable::Rescheme.from(twin_class,
|
24
24
|
recursive: false,
|
25
|
-
definitions_from: lambda { |
|
25
|
+
definitions_from: lambda { |twin_klass| twin_klass.definitions },
|
26
26
|
superclass: Representable::Decorator,
|
27
27
|
include: Representable::Hash,
|
28
28
|
exclude_options: [:default], # TODO: TEST IN default_test.
|
data/lib/disposable/version.rb
CHANGED
data/test/callback_group_test.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require "test_helper"
|
2
2
|
require "disposable/callback"
|
3
|
-
require "pp"
|
4
3
|
|
5
4
|
class CallbackGroupTest < MiniTest::Spec
|
6
5
|
class Group < Disposable::Callback::Group
|
@@ -125,7 +124,7 @@ class CallbackGroupTest < MiniTest::Spec
|
|
125
124
|
|
126
125
|
twin.name = "Dear Landlord"
|
127
126
|
|
128
|
-
group = Group.new(twin).(context:
|
127
|
+
group = Group.new(twin).(context: Operation.new, content: content)
|
129
128
|
# Disposable::Callback::Dispatch.new(twin).on_change{ |twin| puts twin;puts }
|
130
129
|
|
131
130
|
# pp group.invocations
|
@@ -185,7 +184,7 @@ class CallbackGroupInheritanceTest < MiniTest::Spec
|
|
185
184
|
|
186
185
|
it do
|
187
186
|
Group.hooks.size.must_equal 4
|
188
|
-
pp EnhancedGroup.hooks
|
187
|
+
# pp EnhancedGroup.hooks
|
189
188
|
EnhancedGroup.hooks.size.must_equal 6
|
190
189
|
EnhancedGroup.definitions.get(EnhancedGroup.hooks[5][1])[:nested].hooks.to_s.must_equal "[[:on_add, :rewind!, {}]]"
|
191
190
|
end
|
data/test/callbacks_test.rb
CHANGED
@@ -74,9 +74,9 @@ class CallbacksTest < MiniTest::Spec
|
|
74
74
|
|
75
75
|
# for collections.
|
76
76
|
it do
|
77
|
-
album.songs <<
|
77
|
+
album.songs << Song.new
|
78
78
|
album.songs << Song.create(title: "Run For Cover")
|
79
|
-
album.songs <<
|
79
|
+
album.songs << Song.new
|
80
80
|
invokes = []
|
81
81
|
|
82
82
|
Callback.new(twin.songs).on_create { |t| invokes << t }
|
@@ -144,9 +144,9 @@ class CallbacksTest < MiniTest::Spec
|
|
144
144
|
|
145
145
|
# for collections.
|
146
146
|
it do
|
147
|
-
album.songs <<
|
147
|
+
album.songs << Song.new
|
148
148
|
album.songs << Song.create(title: "Run For Cover")
|
149
|
-
album.songs <<
|
149
|
+
album.songs << Song.new
|
150
150
|
|
151
151
|
invokes = []
|
152
152
|
Callback.new(twin.songs).on_update { |t| invokes << t }
|
@@ -350,7 +350,7 @@ class CallbacksTest < MiniTest::Spec
|
|
350
350
|
song = Song.new
|
351
351
|
album.songs = [ex_song, song]
|
352
352
|
|
353
|
-
twin.songs.delete(
|
353
|
+
twin.songs.delete(twin.songs[0])
|
354
354
|
|
355
355
|
Callback.new(twin.songs).on_destroy { |t| invokes << t }
|
356
356
|
invokes.must_equal []
|
data/test/test_helper.rb
CHANGED
@@ -1,9 +1,13 @@
|
|
1
1
|
require "disposable"
|
2
2
|
require "minitest/autorun"
|
3
|
-
require "pp"
|
4
3
|
require "representable/debug"
|
4
|
+
# require "pp"
|
5
5
|
require "declarative/testing"
|
6
6
|
|
7
|
+
require "disposable/twin/coercion"
|
8
|
+
DRY_TYPES_CONSTANT = Disposable::Twin::Coercion::DRY_TYPES_CONSTANT
|
9
|
+
DRY_TYPES_INT_CONSTANT = Disposable::Twin::Coercion::DRY_TYPES_VERSION < 13 ? 'Int' : 'Integer'
|
10
|
+
|
7
11
|
class Track
|
8
12
|
def initialize(options={})
|
9
13
|
@title = options[:title]
|
@@ -12,7 +16,6 @@ class Track
|
|
12
16
|
attr_reader :title
|
13
17
|
end
|
14
18
|
|
15
|
-
|
16
19
|
# require 'active_record'
|
17
20
|
# require 'database_cleaner'
|
18
21
|
# DatabaseCleaner.strategy = :truncation
|
@@ -39,18 +42,18 @@ ActiveRecord::Base.establish_connection(
|
|
39
42
|
ActiveRecord::Schema.define do
|
40
43
|
create_table :artists do |table|
|
41
44
|
table.column :name, :string
|
42
|
-
table.timestamps
|
45
|
+
table.timestamps null: false
|
43
46
|
end
|
44
47
|
create_table :songs do |table|
|
45
48
|
table.column :title, :string
|
46
49
|
table.column :artist_id, :integer
|
47
50
|
table.column :album_id, :integer
|
48
|
-
table.timestamps
|
51
|
+
table.timestamps null: false
|
49
52
|
end
|
50
53
|
create_table :albums do |table|
|
51
54
|
table.column :name, :string
|
52
55
|
table.column :artist_id, :integer
|
53
|
-
table.timestamps
|
56
|
+
table.timestamps null: false
|
54
57
|
end
|
55
58
|
end
|
56
59
|
|
@@ -71,7 +74,7 @@ module Disposable
|
|
71
74
|
end
|
72
75
|
|
73
76
|
def saved?
|
74
|
-
@saved
|
77
|
+
defined?(@saved) ? @saved : nil
|
75
78
|
end
|
76
79
|
end
|
77
80
|
end
|
data/test/twin/changed_test.rb
CHANGED
data/test/twin/coercion_test.rb
CHANGED
@@ -3,16 +3,15 @@ require "test_helper"
|
|
3
3
|
require "disposable/twin/coercion"
|
4
4
|
|
5
5
|
class CoercionTest < MiniTest::Spec
|
6
|
-
|
7
6
|
class TwinWithSkipSetter < Disposable::Twin
|
8
7
|
feature Coercion
|
9
8
|
feature Setup::SkipSetter
|
10
9
|
|
11
10
|
property :id
|
12
|
-
property :released_at, type:
|
11
|
+
property :released_at, type: DRY_TYPES_CONSTANT::DateTime
|
13
12
|
|
14
13
|
property :hit do
|
15
|
-
property :length, type: Types::Coercible
|
14
|
+
property :length, type: const_get("Types::Coercible::#{DRY_TYPES_INT_CONSTANT}")
|
16
15
|
property :good, type: Types::Bool
|
17
16
|
end
|
18
17
|
|
@@ -24,7 +23,6 @@ class CoercionTest < MiniTest::Spec
|
|
24
23
|
end
|
25
24
|
|
26
25
|
describe "with Setup::SkipSetter" do
|
27
|
-
|
28
26
|
subject do
|
29
27
|
TwinWithSkipSetter.new(album)
|
30
28
|
end
|
@@ -54,14 +52,14 @@ class CoercionTest < MiniTest::Spec
|
|
54
52
|
subject.released_at.must_be_kind_of DateTime
|
55
53
|
subject.released_at.must_equal DateTime.parse("30/03/1981")
|
56
54
|
subject.hit.length.must_equal 312
|
57
|
-
subject.hit.good.
|
55
|
+
subject.hit.good.must_be_nil
|
58
56
|
subject.band.label.value.must_equal 9999.99
|
59
57
|
end
|
60
58
|
end
|
61
59
|
|
62
60
|
class TwinWithoutSkipSetter < Disposable::Twin
|
63
61
|
feature Coercion
|
64
|
-
property :id, type: Types::Coercible
|
62
|
+
property :id, type: const_get("Types::Coercible::#{DRY_TYPES_INT_CONSTANT}")
|
65
63
|
end
|
66
64
|
|
67
65
|
describe "without Setup::SkipSetter" do
|
@@ -81,9 +79,9 @@ class CoercionTest < MiniTest::Spec
|
|
81
79
|
feature Coercion
|
82
80
|
|
83
81
|
property :date_of_birth,
|
84
|
-
type:
|
82
|
+
type: DRY_TYPES_CONSTANT::Date, nilify: true
|
85
83
|
property :date_of_death_by_unicorns,
|
86
|
-
type:
|
84
|
+
type: DRY_TYPES_CONSTANT::Nil | DRY_TYPES_CONSTANT::Date
|
87
85
|
property :id, nilify: true
|
88
86
|
end
|
89
87
|
|
@@ -102,33 +100,33 @@ class CoercionTest < MiniTest::Spec
|
|
102
100
|
|
103
101
|
it "coerce empty values to nil when using option nilify: true" do
|
104
102
|
subject.date_of_birth = ""
|
105
|
-
subject.date_of_birth.
|
103
|
+
subject.date_of_birth.must_be_nil
|
106
104
|
end
|
107
105
|
|
108
106
|
it "coerce empty values to nil when using dry-types | operator" do
|
109
107
|
subject.date_of_death_by_unicorns = ""
|
110
|
-
subject.date_of_death_by_unicorns.
|
108
|
+
subject.date_of_death_by_unicorns.must_be_nil
|
111
109
|
end
|
112
110
|
|
113
111
|
it "converts blank string to nil, without :type option" do
|
114
112
|
subject.id = ""
|
115
|
-
subject.id.
|
113
|
+
subject.id.must_be_nil
|
116
114
|
end
|
117
115
|
end
|
118
116
|
end
|
119
117
|
|
120
118
|
# this converts "" to nil and then breaks because it's strict.
|
121
|
-
# Types::Strict::String.constructor(Dry::Types::
|
119
|
+
# Types::Strict::String.constructor(Dry::Types::Params.method(:to_nil))
|
122
120
|
|
123
121
|
class CoercionTypingTest < MiniTest::Spec
|
124
122
|
class Song < Disposable::Twin
|
125
123
|
include Coercion
|
126
124
|
include Setup::SkipSetter
|
127
125
|
|
128
|
-
# property :title, type: Dry::Types::Strict::String.constructor(Dry::Types::
|
126
|
+
# property :title, type: Dry::Types::Strict::String.constructor(Dry::Types::Params.method(:to_nil))
|
129
127
|
property :title, type: Types::Strict::String.optional # this is the behavior of the "DB" data twin. this is NOT the form.
|
130
128
|
|
131
|
-
# property :name, type: Types::
|
129
|
+
# property :name, type: Types::Params::String
|
132
130
|
end
|
133
131
|
|
134
132
|
it do
|
@@ -155,12 +153,14 @@ class CoercionTypingTest < MiniTest::Spec
|
|
155
153
|
include Setup::SkipSetter
|
156
154
|
|
157
155
|
|
158
|
-
# property :title, type: Dry::Types::Strict::String.constructor(Dry::Types::
|
159
|
-
|
156
|
+
# property :title, type: Dry::Types::Strict::String.constructor(Dry::Types::Params.method(:to_nil))
|
157
|
+
|
158
|
+
constructor = Disposable::Twin::Coercion::DRY_TYPES_VERSION < 13 ? 'form.nil' : 'params.nil'
|
159
|
+
property :title, type: Types::Strict::String.optional.constructor(Dry::Types[constructor]) # this is the behavior of the "DB" data twin. this is NOT the form.
|
160
160
|
|
161
|
-
# property :name, type: Types::
|
161
|
+
# property :name, type: Types::Params::String
|
162
162
|
|
163
|
-
property :enabled, type:
|
163
|
+
property :enabled, type: DRY_TYPES_CONSTANT::Bool
|
164
164
|
# property :enabled, Bool.constructor(:trim!)
|
165
165
|
end
|
166
166
|
it do
|
@@ -44,7 +44,7 @@ class TwinCollectionTest < MiniTest::Spec
|
|
44
44
|
let (:album) { Model::Album.new(1, "The Rest Is Silence", [Model::Song.new(3), Model::Song.new(4)]) }
|
45
45
|
let (:twin) { Twin::Album.new(album) }
|
46
46
|
|
47
|
-
it { twin.songs.find_by(id: 1).
|
47
|
+
it { twin.songs.find_by(id: 1).must_be_nil }
|
48
48
|
it { twin.songs.find_by(id: 3).must_equal twin.songs[0] }
|
49
49
|
it { twin.songs.find_by(id: 4).must_equal twin.songs[1] }
|
50
50
|
it { twin.songs.find_by(id: "4").must_equal twin.songs[1] }
|
@@ -172,7 +172,7 @@ class TwinCollectionActiveRecordTest < MiniTest::Spec
|
|
172
172
|
twin.songs.added.must_equal []
|
173
173
|
twin.songs << song2
|
174
174
|
twin.songs.added.must_equal [twin.songs[1]]
|
175
|
-
twin.songs.insert(2,
|
175
|
+
twin.songs.insert(2, Song.new)
|
176
176
|
twin.songs.added.must_equal [twin.songs[1], twin.songs[2]]
|
177
177
|
|
178
178
|
# TODO: what to do if we override an item (insert)?
|
@@ -180,7 +180,7 @@ class TwinCollectionActiveRecordTest < MiniTest::Spec
|
|
180
180
|
end
|
181
181
|
|
182
182
|
describe "#deleted" do
|
183
|
-
let (:album) { Album.create(name: "The Rest Is Silence", songs: [song1, song2,
|
183
|
+
let (:album) { Album.create(name: "The Rest Is Silence", songs: [song1, song2, Song.new]) }
|
184
184
|
|
185
185
|
it do
|
186
186
|
twin = Twin::Album.new(album)
|
data/test/twin/hash_test.rb
CHANGED
@@ -33,9 +33,9 @@ class HashTest < MiniTest::Spec
|
|
33
33
|
|
34
34
|
song = Song.new(model)
|
35
35
|
song.id.must_equal 1
|
36
|
-
song.content.title.
|
37
|
-
song.content.band.name.
|
38
|
-
song.content.band.label.location.
|
36
|
+
song.content.title.must_be_nil
|
37
|
+
song.content.band.name.must_be_nil
|
38
|
+
song.content.band.label.location.must_be_nil
|
39
39
|
song.content.releases.must_equal []
|
40
40
|
|
41
41
|
# model's hash hasn't changed.
|
@@ -48,9 +48,9 @@ class HashTest < MiniTest::Spec
|
|
48
48
|
|
49
49
|
song = Song.new(model)
|
50
50
|
song.id.must_equal 1
|
51
|
-
song.content.title.
|
52
|
-
song.content.band.name.
|
53
|
-
song.content.band.label.location.
|
51
|
+
song.content.title.must_be_nil
|
52
|
+
song.content.band.name.must_be_nil
|
53
|
+
song.content.band.label.location.must_be_nil
|
54
54
|
|
55
55
|
# model's hash hasn't changed.
|
56
56
|
model.inspect.must_equal "#<struct HashTest::Model id=1, content=nil>"
|
@@ -137,7 +137,7 @@ class HashTest < MiniTest::Spec
|
|
137
137
|
include Property::Hash
|
138
138
|
feature Coercion
|
139
139
|
|
140
|
-
property :id, type: Types::Coercible
|
140
|
+
property :id, type: const_get("Types::Coercible::#{DRY_TYPES_INT_CONSTANT}")
|
141
141
|
property :content, field: :hash do
|
142
142
|
property :title
|
143
143
|
property :band do
|
@@ -161,7 +161,7 @@ class HashTest < MiniTest::Spec
|
|
161
161
|
include Property::Hash
|
162
162
|
|
163
163
|
property :id
|
164
|
-
|
164
|
+
property :content, field: :hash do
|
165
165
|
property :title
|
166
166
|
property :band do
|
167
167
|
property :name
|
@@ -198,12 +198,59 @@ class HashTest < MiniTest::Spec
|
|
198
198
|
song.content.title.must_equal "Notorious"
|
199
199
|
|
200
200
|
# singular nested accessors
|
201
|
-
song.band.name.
|
202
|
-
song.content.band.name.
|
201
|
+
song.band.name.must_be_nil
|
202
|
+
song.content.band.name.must_be_nil
|
203
203
|
song.band.name = "Duran Duran"
|
204
204
|
song.band.name.must_equal "Duran Duran"
|
205
205
|
end
|
206
206
|
end
|
207
|
+
|
208
|
+
describe 'collection schema' do
|
209
|
+
AlbumModel = Struct.new(:id, :songs)
|
210
|
+
class Album < Disposable::Twin
|
211
|
+
feature Sync
|
212
|
+
feature Property::Hash
|
213
|
+
|
214
|
+
property :id
|
215
|
+
collection :songs, field: :hash do
|
216
|
+
property :title
|
217
|
+
property :band do
|
218
|
+
property :name
|
219
|
+
|
220
|
+
property :label do
|
221
|
+
property :location
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
collection :featured_artists do
|
226
|
+
property :name
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
it "exposes reader and writer" do
|
232
|
+
model = AlbumModel.new(1, [
|
233
|
+
{ title: "Sherry", band: { name: 'The Four Seasons', label: { location: 'US' } }, featured_artists: [{ name: 'Frankie Valli' }, { name: 'The Variatones' }] },
|
234
|
+
{ title: "Walk Like a Man", band: { name: 'The Four Seasons', label: { location: 'US' } }, featured_artists: [{ name: 'Frankie Valli' }] }
|
235
|
+
])
|
236
|
+
contract = Album.new(model)
|
237
|
+
|
238
|
+
song1 = contract.songs[0]
|
239
|
+
|
240
|
+
song1.title.must_equal "Sherry"
|
241
|
+
song1.band.name.must_equal 'The Four Seasons'
|
242
|
+
song1.band.label.location.must_equal 'US'
|
243
|
+
song1.featured_artists[0].name.must_equal 'Frankie Valli'
|
244
|
+
song1.featured_artists[1].name.must_equal 'The Variatones'
|
245
|
+
|
246
|
+
song2 = contract.songs[1]
|
247
|
+
|
248
|
+
song2.title.must_equal "Walk Like a Man"
|
249
|
+
song2.band.name.must_equal 'The Four Seasons'
|
250
|
+
song2.band.label.location.must_equal 'US'
|
251
|
+
song2.featured_artists[0].name.must_equal 'Frankie Valli'
|
252
|
+
end
|
253
|
+
end
|
207
254
|
end
|
208
255
|
|
209
256
|
# fixme: make sure default hash is different for every invocation, and not created at compile time.
|
data/test/twin/option_test.rb
CHANGED
@@ -28,7 +28,7 @@
|
|
28
28
|
# # option is not delegated to model.
|
29
29
|
# it { twin.preview?.must_equal false }
|
30
30
|
# # not passing option means zero.
|
31
|
-
# it { twin.current_user.
|
31
|
+
# it { twin.current_user.must_be_nil }
|
32
32
|
|
33
33
|
# describe "passing all options" do
|
34
34
|
# let (:twin) { Song.new(song, :preview? => false, current_user: Object) }
|
data/test/twin/parent_test.rb
CHANGED
@@ -27,14 +27,14 @@ class TwinParentTest < MiniTest::Spec
|
|
27
27
|
|
28
28
|
let (:album) { Album.new(Model::Album.new(1, Model::Artist.new("Helloween"), [Model::Song.new("I'm Alive", Model::Artist.new("Kai Hansen"))])) }
|
29
29
|
|
30
|
-
it { album.parent.
|
30
|
+
it { album.parent.must_be_nil }
|
31
31
|
it { album.artist.parent.must_equal album }
|
32
32
|
it { album.songs[0].parent.must_equal album }
|
33
33
|
it { album.songs[0].composer.parent.must_equal album.songs[0] }
|
34
34
|
|
35
35
|
describe "Collection#append" do
|
36
36
|
it do
|
37
|
-
album.songs.append(
|
37
|
+
album.songs.append(Model::Song.new)
|
38
38
|
album.songs[1].parent.must_equal album
|
39
39
|
end
|
40
40
|
end
|
@@ -5,7 +5,7 @@ class PropertyProcessorTest < Minitest::Spec
|
|
5
5
|
Artist = Struct.new(:name)
|
6
6
|
Song = Struct.new(:id)
|
7
7
|
|
8
|
-
|
8
|
+
class AlbumTwin < Disposable::Twin
|
9
9
|
property :title
|
10
10
|
|
11
11
|
property :artist do
|
@@ -35,7 +35,7 @@ class PropertyProcessorTest < Minitest::Spec
|
|
35
35
|
|
36
36
|
it "allows nil collection" do
|
37
37
|
twin = AlbumTwin.new(Album.new("Live!", Artist.new, nil))
|
38
|
-
|
38
|
+
|
39
39
|
called = []
|
40
40
|
Disposable::Twin::PropertyProcessor.new(twin.class.definitions.get(:songs), twin).() { |v, i| called << [v.model, i] }
|
41
41
|
|
data/test/twin/readable_test.rb
CHANGED
@@ -30,9 +30,9 @@ class ReadableTest < MiniTest::Spec
|
|
30
30
|
let (:twin) { PasswordForm.new(cred) }
|
31
31
|
|
32
32
|
it {
|
33
|
-
twin.password.
|
33
|
+
twin.password.must_be_nil # not readable.
|
34
34
|
twin.credit_card.name.must_equal "Jonny"
|
35
|
-
twin.credit_card.number.
|
35
|
+
twin.credit_card.number.must_be_nil # not readable.
|
36
36
|
|
37
37
|
# manual setting on the twin works.
|
38
38
|
twin.password = "123"
|
data/test/twin/save_test.rb
CHANGED
@@ -88,19 +88,19 @@ class SaveTest < MiniTest::Spec
|
|
88
88
|
nested_hash.must_equal({"name"=>"Live And Dangerous", "songs"=>[{"title"=>"Southbound", "composer"=>nil}, {"title"=>"The Boys Are Back In Town", "composer"=>{"name"=>"Lynott"}}], "artist"=>{"name"=>"Thin Lizzy"}})
|
89
89
|
|
90
90
|
# nothing written to model.
|
91
|
-
album.name.
|
92
|
-
album.songs[0].title.
|
93
|
-
album.songs[1].title.
|
94
|
-
album.songs[1].composer.name.
|
95
|
-
album.artist.name.
|
91
|
+
album.name.must_be_nil
|
92
|
+
album.songs[0].title.must_be_nil
|
93
|
+
album.songs[1].title.must_be_nil
|
94
|
+
album.songs[1].composer.name.must_be_nil
|
95
|
+
album.artist.name.must_be_nil
|
96
96
|
|
97
97
|
# nothing saved.
|
98
98
|
# saved?
|
99
|
-
album.saved?.
|
100
|
-
album.songs[0].saved?.
|
101
|
-
album.songs[1].saved?.
|
102
|
-
album.songs[1].composer.saved?.
|
103
|
-
album.artist.saved?.
|
99
|
+
album.saved?.must_be_nil
|
100
|
+
album.songs[0].saved?.must_be_nil
|
101
|
+
album.songs[1].saved?.must_be_nil
|
102
|
+
album.songs[1].composer.saved?.must_be_nil
|
103
|
+
album.artist.saved?.must_be_nil
|
104
104
|
end
|
105
105
|
|
106
106
|
|
@@ -148,9 +148,9 @@ class SaveTest < MiniTest::Spec
|
|
148
148
|
|
149
149
|
# saved?
|
150
150
|
album.saved?.must_equal true
|
151
|
-
album.songs[0].saved?.
|
152
|
-
album.songs[1].saved?.
|
153
|
-
album.songs[1].composer.saved?.
|
151
|
+
album.songs[0].saved?.must_be_nil
|
152
|
+
album.songs[1].saved?.must_be_nil
|
153
|
+
album.songs[1].composer.saved?.must_be_nil # doesn't get saved.
|
154
154
|
album.artist.saved?.must_equal true
|
155
155
|
end
|
156
156
|
|
@@ -186,7 +186,7 @@ end
|
|
186
186
|
# form.save(length: lambda { |value, options| form.model.id = "#{value}: #{length_seconds}" })
|
187
187
|
|
188
188
|
# song.title.must_equal "A Poor Man's Memory"
|
189
|
-
# song.length.
|
189
|
+
# song.length.must_be_nil
|
190
190
|
# song.id.must_equal "10: 120"
|
191
191
|
# end
|
192
192
|
# end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
require "disposable/twin/coercion"
|
3
|
+
require "disposable/twin/property/struct"
|
4
|
+
|
5
|
+
class StructCoercionTest < Minitest::Spec
|
6
|
+
ExpenseModel = Struct.new(:content)
|
7
|
+
|
8
|
+
class Expense < Disposable::Twin
|
9
|
+
feature Property::Struct
|
10
|
+
feature Coercion
|
11
|
+
|
12
|
+
property :content do
|
13
|
+
property :amount, type: DRY_TYPES_CONSTANT::Float
|
14
|
+
end
|
15
|
+
|
16
|
+
unnest :amount, from: :content
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
it do
|
21
|
+
twin = Expense.new( ExpenseModel.new({}) )
|
22
|
+
|
23
|
+
#- direct access, without unnest
|
24
|
+
twin.content.amount.must_be_nil
|
25
|
+
twin.content.amount = "1.8"
|
26
|
+
twin.content.amount.must_equal 1.8
|
27
|
+
end
|
28
|
+
|
29
|
+
it "via unnest" do
|
30
|
+
twin = Expense.new( ExpenseModel.new({}) )
|
31
|
+
|
32
|
+
twin.amount.must_be_nil
|
33
|
+
twin.amount = "1.8"
|
34
|
+
twin.amount.must_equal 1.8
|
35
|
+
end
|
36
|
+
end
|
data/test/twin/struct_test.rb
CHANGED
@@ -12,7 +12,7 @@ class TwinStructTest < MiniTest::Spec
|
|
12
12
|
|
13
13
|
# empty hash
|
14
14
|
# it { Song.new({}).number.must_equal 1 }
|
15
|
-
it { Song.new({}).number.
|
15
|
+
it { Song.new({}).number.must_be_nil } # TODO: implement default.
|
16
16
|
|
17
17
|
# model hash
|
18
18
|
it { Song.new(number: 2).number.must_equal 2 }
|
@@ -179,7 +179,7 @@ class StructReadableWriteableTest < Minitest::Spec
|
|
179
179
|
it "ignores readable: false" do
|
180
180
|
song = Song.new(length: 123, id: 1)
|
181
181
|
song.length.must_equal 123
|
182
|
-
song.id.
|
182
|
+
song.id.must_be_nil
|
183
183
|
end
|
184
184
|
|
185
185
|
it "ignores writeable: false" do
|
@@ -58,7 +58,7 @@
|
|
58
58
|
# # Album#name :sync was called, first case.
|
59
59
|
# album.name.must_equal "processed+Run For Cover"
|
60
60
|
# # Song#title :sync called but returns nil.
|
61
|
-
# song.title.
|
61
|
+
# song.title.must_be_nil
|
62
62
|
# # Song#title :sync called and processed, first case.
|
63
63
|
# song_with_composer.title.must_equal "++Empty Rooms"
|
64
64
|
|
@@ -139,7 +139,7 @@
|
|
139
139
|
# # Album#name :sync was called, first case.
|
140
140
|
# album.name.must_equal "processed+Run For Cover"
|
141
141
|
# # Song#title :sync called but returns nil.
|
142
|
-
# song.title.
|
142
|
+
# song.title.must_be_nil
|
143
143
|
# # Song#title :sync called and processed, first case.
|
144
144
|
# #### song_with_composer.title.must_equal "++Empty Rooms"
|
145
145
|
|
data/test/twin/sync_test.rb
CHANGED
@@ -47,11 +47,11 @@ class TwinSyncTest < MiniTest::Spec
|
|
47
47
|
fill_out!(twin)
|
48
48
|
|
49
49
|
# not written to model, yet.
|
50
|
-
album.name.
|
51
|
-
album.songs[0].title.
|
52
|
-
album.songs[1].title.
|
53
|
-
album.songs[1].composer.name.
|
54
|
-
album.artist.name.
|
50
|
+
album.name.must_be_nil
|
51
|
+
album.songs[0].title.must_be_nil
|
52
|
+
album.songs[1].title.must_be_nil
|
53
|
+
album.songs[1].composer.name.must_be_nil
|
54
|
+
album.artist.name.must_be_nil
|
55
55
|
|
56
56
|
twin.sync
|
57
57
|
|
@@ -82,9 +82,9 @@ class TwinSyncTest < MiniTest::Spec
|
|
82
82
|
twin.songs[1].composer.name = "Lynott"
|
83
83
|
|
84
84
|
# not written to model, yet.
|
85
|
-
album.name.
|
85
|
+
album.name.must_be_nil
|
86
86
|
album.songs.must_equal []
|
87
|
-
album.artist.
|
87
|
+
album.artist.must_be_nil
|
88
88
|
|
89
89
|
twin.sync # this assigns a new collection via #songs=.
|
90
90
|
|
@@ -110,11 +110,11 @@ class TwinSyncTest < MiniTest::Spec
|
|
110
110
|
nested_hash.must_equal({"name"=>"Live And Dangerous", "songs"=>[{"title"=>"Southbound", "composer"=>nil}, {"title"=>"The Boys Are Back In Town", "composer"=>{"name"=>"Lynott"}}], "artist"=>{"name"=>"Thin Lizzy"}})
|
111
111
|
|
112
112
|
# nothing written to model.
|
113
|
-
album.name.
|
114
|
-
album.songs[0].title.
|
115
|
-
album.songs[1].title.
|
116
|
-
album.songs[1].composer.name.
|
117
|
-
album.artist.name.
|
113
|
+
album.name.must_be_nil
|
114
|
+
album.songs[0].title.must_be_nil
|
115
|
+
album.songs[1].title.must_be_nil
|
116
|
+
album.songs[1].composer.name.must_be_nil
|
117
|
+
album.artist.name.must_be_nil
|
118
118
|
end
|
119
119
|
|
120
120
|
describe "nil values" do
|
data/test/twin/twin_test.rb
CHANGED
@@ -75,12 +75,12 @@ class TwinTest < MiniTest::Spec
|
|
75
75
|
|
76
76
|
describe "deleting" do
|
77
77
|
it "allows overwriting nested twin with nil" do
|
78
|
-
album = Model::Album.new(1, "Uncertain Terms", [],
|
78
|
+
album = Model::Album.new(1, "Uncertain Terms", [], Model::Artist.new("Greg Howe"))
|
79
79
|
twin = Twin::Album.new(album)
|
80
80
|
twin.artist.id.must_equal "Greg Howe"
|
81
81
|
|
82
82
|
twin.artist = nil
|
83
|
-
twin.artist.
|
83
|
+
twin.artist.must_be_nil
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
data/test/twin/unnest_test.rb
CHANGED
@@ -25,12 +25,12 @@ class UnnestTest < MiniTest::Spec
|
|
25
25
|
it "exposes accessors on top-level twin" do
|
26
26
|
twin = Twin.new(OpenStruct.new(content: OpenStruct.new()))
|
27
27
|
|
28
|
-
twin.email.
|
28
|
+
twin.email.must_be_nil
|
29
29
|
twin.email= 2
|
30
30
|
twin.email.model.must_equal 2
|
31
31
|
|
32
32
|
|
33
|
-
twin.id.
|
33
|
+
twin.id.must_be_nil
|
34
34
|
twin.id = 1
|
35
35
|
twin.id.must_equal 1
|
36
36
|
end
|
data/test/twin/virtual_test.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: disposable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Sutterer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-06-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: uber
|
@@ -138,16 +138,16 @@ dependencies:
|
|
138
138
|
name: activerecord
|
139
139
|
requirement: !ruby/object:Gem::Requirement
|
140
140
|
requirements:
|
141
|
-
- -
|
141
|
+
- - ">="
|
142
142
|
- !ruby/object:Gem::Version
|
143
|
-
version:
|
143
|
+
version: '0'
|
144
144
|
type: :development
|
145
145
|
prerelease: false
|
146
146
|
version_requirements: !ruby/object:Gem::Requirement
|
147
147
|
requirements:
|
148
|
-
- -
|
148
|
+
- - ">="
|
149
149
|
- !ruby/object:Gem::Version
|
150
|
-
version:
|
150
|
+
version: '0'
|
151
151
|
- !ruby/object:Gem::Dependency
|
152
152
|
name: sqlite3
|
153
153
|
requirement: !ruby/object:Gem::Requirement
|
@@ -166,16 +166,16 @@ dependencies:
|
|
166
166
|
name: dry-types
|
167
167
|
requirement: !ruby/object:Gem::Requirement
|
168
168
|
requirements:
|
169
|
-
- - "
|
169
|
+
- - ">="
|
170
170
|
- !ruby/object:Gem::Version
|
171
|
-
version: '0
|
171
|
+
version: '0'
|
172
172
|
type: :development
|
173
173
|
prerelease: false
|
174
174
|
version_requirements: !ruby/object:Gem::Requirement
|
175
175
|
requirements:
|
176
|
-
- - "
|
176
|
+
- - ">="
|
177
177
|
- !ruby/object:Gem::Version
|
178
|
-
version: '0
|
178
|
+
version: '0'
|
179
179
|
description: Decorators on top of your ORM layer.
|
180
180
|
email:
|
181
181
|
- apotonick@gmail.com
|
@@ -251,6 +251,7 @@ files:
|
|
251
251
|
- test/twin/save_test.rb
|
252
252
|
- test/twin/setup_test.rb
|
253
253
|
- test/twin/skip_unchanged_test.rb
|
254
|
+
- test/twin/struct/coercion_test.rb
|
254
255
|
- test/twin/struct_test.rb
|
255
256
|
- test/twin/sync_option_test.rb
|
256
257
|
- test/twin/sync_test.rb
|
@@ -278,7 +279,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
278
279
|
version: '0'
|
279
280
|
requirements: []
|
280
281
|
rubyforge_project:
|
281
|
-
rubygems_version: 2.
|
282
|
+
rubygems_version: 2.6.14
|
282
283
|
signing_key:
|
283
284
|
specification_version: 4
|
284
285
|
summary: Decorators on top of your ORM layer with change tracking, collection semantics
|
@@ -315,6 +316,7 @@ test_files:
|
|
315
316
|
- test/twin/save_test.rb
|
316
317
|
- test/twin/setup_test.rb
|
317
318
|
- test/twin/skip_unchanged_test.rb
|
319
|
+
- test/twin/struct/coercion_test.rb
|
318
320
|
- test/twin/struct_test.rb
|
319
321
|
- test/twin/sync_option_test.rb
|
320
322
|
- test/twin/sync_test.rb
|