disposable 0.4.3 → 0.4.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 +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
|