disposable 0.1.15 → 0.2.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -1
- data/CHANGES.md +5 -2
- data/Gemfile +6 -4
- data/disposable.gemspec +2 -1
- data/lib/disposable/callback.rb +19 -26
- data/lib/disposable/expose.rb +3 -3
- data/lib/disposable/{twin/schema.rb → rescheme.rb} +11 -11
- data/lib/disposable/twin/changed.rb +1 -1
- data/lib/disposable/twin/composition.rb +3 -3
- data/lib/disposable/twin/definitions.rb +28 -0
- data/lib/disposable/twin/setup.rb +6 -5
- data/lib/disposable/twin/struct.rb +2 -2
- data/lib/disposable/twin/sync.rb +20 -11
- data/lib/disposable/twin.rb +20 -55
- data/lib/disposable/version.rb +1 -1
- data/lib/disposable.rb +1 -0
- data/test/callback_group_test.rb +14 -13
- data/test/expose_test.rb +2 -2
- data/test/{twin/schema_test.rb → rescheme_test.rb} +34 -36
- data/test/test_helper.rb +3 -2
- data/test/twin/collection_test.rb +5 -5
- data/test/twin/feature_test.rb +0 -4
- data/test/twin/inherit_test.rb +2 -2
- data/test/twin/process_inline_test.rb +26 -26
- data/test/twin/setup_test.rb +3 -3
- data/test/twin/twin_test.rb +10 -25
- metadata +26 -13
- data/lib/disposable/twin/option.rb +0 -12
- data/lib/disposable/twin/representer.rb +0 -57
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a33b386392c77411ef19323562c9f0bb3b31761c
|
4
|
+
data.tar.gz: 789982e39d11feb8a4550e93452ca8d9ba91ac07
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eb94a6c5097a5b380011f9a6cf6f6b02081b058842751110beec5b2f82cc37fc088f08d8b3ea2b8fb3d87e8607c9e44acc446d52470394f4ca27736cf8c29891
|
7
|
+
data.tar.gz: d11e58f841ecccfb165f6c48e6ddeb65eb3e9fe8b4aade955b6fc906bd056abc63589c9d42f05c1a35effb45becd6d0a6a616a171c81797d28fce1ac871895cf
|
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
-
# 0.
|
1
|
+
# 0.2.0
|
2
2
|
|
3
|
-
*
|
3
|
+
* Internally, use [Declarative](https://github.com/apotonick/declarative) now for schema creation, resulting in the following internal changes.
|
4
|
+
* `Twin::representer_class.representable_attrs` is now `Twin::definitions`.
|
5
|
+
* `Disposable::Twin::Schema` is now `Disposable::Rescheme`. Renamed its `:representer_from` option to `:definitions_from`.
|
6
|
+
* `twin: Twin::Song` is the only way to specify an external twin. To reduce complexity, I've removed the lambda version of `:twin`.
|
4
7
|
|
5
8
|
# 0.1.14
|
6
9
|
|
data/Gemfile
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
source
|
2
|
-
|
3
|
-
# Specify your gem's dependencies in disposable.gemspec
|
1
|
+
source "https://rubygems.org"
|
4
2
|
gemspec
|
5
3
|
|
6
|
-
|
4
|
+
# gem "representable", path: "../representable"
|
5
|
+
gem "representable", github: "apotonick/representable"
|
6
|
+
# gem "declarative", path: "../declarative"
|
7
|
+
# gem "declarative", github: "apotonick/declarative"
|
8
|
+
gem "minitest-line"
|
data/disposable.gemspec
CHANGED
@@ -19,7 +19,8 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_dependency "uber"
|
22
|
-
spec.add_dependency "
|
22
|
+
spec.add_dependency "declarative", "~> 0.0.4"
|
23
|
+
spec.add_dependency "representable", ">= 2.4.0.rc1", "< 2.5.0"
|
23
24
|
|
24
25
|
spec.add_development_dependency "bundler", "~> 1.3"
|
25
26
|
spec.add_development_dependency "rake"
|
data/lib/disposable/callback.rb
CHANGED
@@ -12,26 +12,16 @@ module Disposable::Callback
|
|
12
12
|
# you can call collection :songs again, with :inherit. TODO: verify.
|
13
13
|
|
14
14
|
class Group
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
# class << self
|
20
|
-
# include Representable::Cloneable
|
21
|
-
# end
|
22
|
-
self.representer_class = Class.new(Representable::Decorator) do
|
23
|
-
def self.default_inline_class
|
24
|
-
Group.extend Representable::Cloneable
|
25
|
-
end
|
15
|
+
extend Declarative::Schema
|
16
|
+
|
17
|
+
def self.default_nested_class
|
18
|
+
Group
|
26
19
|
end
|
27
20
|
|
28
21
|
def self.clone
|
29
22
|
Class.new(self)
|
30
23
|
end
|
31
24
|
|
32
|
-
def self.feature(*args)
|
33
|
-
end
|
34
|
-
|
35
25
|
def self.collection(name, options={}, &block)
|
36
26
|
property(name, options.merge(collection: true), &block)
|
37
27
|
end
|
@@ -42,9 +32,9 @@ module Disposable::Callback
|
|
42
32
|
# it should have a Definition per callback where the representer_module will be a nested Group or a Callback.
|
43
33
|
inherit = options[:inherit] # FIXME: this is deleted in ::property.
|
44
34
|
|
45
|
-
|
35
|
+
super(name, options, &block).tap do |dfn|
|
46
36
|
return if inherit
|
47
|
-
hooks << ["property", dfn
|
37
|
+
hooks << ["property", dfn[:name]]
|
48
38
|
end
|
49
39
|
end
|
50
40
|
|
@@ -60,12 +50,16 @@ module Disposable::Callback
|
|
60
50
|
|
61
51
|
attr_reader :invocations
|
62
52
|
|
63
|
-
|
64
|
-
|
53
|
+
def self.hooks
|
54
|
+
@hooks ||= []
|
55
|
+
end
|
56
|
+
|
65
57
|
|
66
58
|
class << self
|
67
59
|
%w(on_add on_delete on_destroy on_update on_create on_change).each do |event|
|
68
60
|
define_method event do |*args|
|
61
|
+
heritage.record(event, *args)
|
62
|
+
|
69
63
|
hooks << [event.to_sym, args]
|
70
64
|
end
|
71
65
|
end
|
@@ -73,14 +67,13 @@ module Disposable::Callback
|
|
73
67
|
|
74
68
|
|
75
69
|
def call(options={})
|
76
|
-
self.class.hooks.each do |
|
77
|
-
event, args = cfg
|
78
|
-
|
70
|
+
self.class.hooks.each do |event, args|
|
79
71
|
if event == "property" # FIXME: make nicer.
|
80
|
-
definition = self.class.
|
81
|
-
twin = @twin.send(definition
|
72
|
+
definition = self.class.definitions.get(args)
|
73
|
+
twin = @twin.send(definition[:name]) # album.songs
|
82
74
|
|
83
|
-
|
75
|
+
# recursively call nested group.
|
76
|
+
@invocations += definition[:nested].new(twin).(options).invocations # Group.new(twin).()
|
84
77
|
next
|
85
78
|
end
|
86
79
|
|
@@ -108,7 +101,7 @@ module Disposable::Callback
|
|
108
101
|
# Implements the binding between the Callback API (on_change) and the underlying layer (twin/AR/etc.).
|
109
102
|
class Dispatch
|
110
103
|
def initialize(twins)
|
111
|
-
@twins = twins
|
104
|
+
@twins = Array(twins) # TODO: find that out with Collection.
|
112
105
|
@invocations = []
|
113
106
|
end
|
114
107
|
|
@@ -175,4 +168,4 @@ module Disposable::Callback
|
|
175
168
|
end
|
176
169
|
end
|
177
170
|
end
|
178
|
-
end
|
171
|
+
end
|
data/lib/disposable/expose.rb
CHANGED
@@ -13,8 +13,8 @@ module Disposable
|
|
13
13
|
# AlbumExpose.new(OpenStruct.new(title: "AFI")).name #=> "AFI"
|
14
14
|
class Expose
|
15
15
|
class << self
|
16
|
-
def from(
|
17
|
-
|
16
|
+
def from(schema)
|
17
|
+
schema.each do |definition|
|
18
18
|
process_definition!(definition)
|
19
19
|
end
|
20
20
|
self
|
@@ -22,7 +22,7 @@ module Disposable
|
|
22
22
|
|
23
23
|
private
|
24
24
|
def process_definition!(definition)
|
25
|
-
public_name = definition
|
25
|
+
public_name = definition[:name]
|
26
26
|
private_name = definition[:private_name] || public_name
|
27
27
|
|
28
28
|
accessors!(public_name, private_name, definition)
|
@@ -1,13 +1,13 @@
|
|
1
|
-
#
|
1
|
+
# Rescheme::from allows to copy a schema structure. This will create "fresh" inline schemas instead
|
2
2
|
# of inheriting/copying the original classes, making it a replication of the structure, only.
|
3
3
|
#
|
4
|
-
# Options allow to customize the copied
|
4
|
+
# Options allow to customize the copied schema.
|
5
5
|
#
|
6
6
|
# +:exclude+: ignore options from original Definition when copying.
|
7
7
|
#
|
8
8
|
# Provided block is run per newly created Definition.
|
9
|
-
#
|
10
|
-
class Disposable::
|
9
|
+
# Rescheme.from(...) { |dfn| dfn[:readable] = true }
|
10
|
+
class Disposable::Rescheme
|
11
11
|
def self.from(*args, &block)
|
12
12
|
new.from(*args, &block)
|
13
13
|
end
|
@@ -16,9 +16,9 @@ class Disposable::Twin::Schema
|
|
16
16
|
def from(source_class, options, &block) # TODO: can we re-use this for all the decorator logic in #validate, etc?
|
17
17
|
representer = build_representer(options)
|
18
18
|
|
19
|
-
|
19
|
+
definitions = options[:definitions_from].call(source_class)
|
20
20
|
|
21
|
-
|
21
|
+
definitions.each do |dfn|
|
22
22
|
dfn = build_definition!(options, dfn, representer, &block)
|
23
23
|
evaluate_block!(options, dfn, &block)
|
24
24
|
end
|
@@ -41,7 +41,7 @@ private
|
|
41
41
|
new_options.merge!(local_options)
|
42
42
|
|
43
43
|
return from_scalar!(options, source_dfn, new_options, representer) if options[:recursive]==false
|
44
|
-
return from_scalar!(options, source_dfn, new_options, representer) unless source_dfn[:
|
44
|
+
return from_scalar!(options, source_dfn, new_options, representer) unless source_dfn[:nested]
|
45
45
|
from_inline!(options, source_dfn, new_options, representer, &block)
|
46
46
|
end
|
47
47
|
|
@@ -52,14 +52,14 @@ private
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def from_scalar!(options, dfn, new_options, representer)
|
55
|
-
representer.property(dfn
|
55
|
+
representer.property(dfn[:name], new_options)
|
56
56
|
end
|
57
57
|
|
58
58
|
def from_inline!(options, dfn, new_options, representer, &block)
|
59
|
-
nested = dfn[:
|
60
|
-
dfn_options = new_options.merge(
|
59
|
+
nested = dfn[:nested]#.evaluate(nil) # nested now can be a Decorator, a representer module, a Form, a Twin.
|
60
|
+
dfn_options = new_options.merge(nested: from(nested, options, &block))
|
61
61
|
|
62
|
-
representer.property(dfn
|
62
|
+
representer.property(dfn[:name], dfn_options)
|
63
63
|
end
|
64
64
|
|
65
65
|
def evaluate_block!(options, definition)
|
@@ -6,7 +6,7 @@ module Disposable
|
|
6
6
|
module Expose
|
7
7
|
module ClassMethods
|
8
8
|
def expose_class
|
9
|
-
@expose_class ||= Class.new(Disposable::Expose).from(
|
9
|
+
@expose_class ||= Class.new(Disposable::Expose).from(definitions.values)
|
10
10
|
end
|
11
11
|
end # ClassMethods.
|
12
12
|
|
@@ -26,7 +26,7 @@ module Disposable
|
|
26
26
|
module Composition
|
27
27
|
module ClassMethods
|
28
28
|
def expose_class
|
29
|
-
@expose_class ||= Class.new(Disposable::Composition).from(
|
29
|
+
@expose_class ||= Class.new(Disposable::Composition).from(definitions.values)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -39,7 +39,7 @@ module Disposable
|
|
39
39
|
hash = {}
|
40
40
|
|
41
41
|
@model.each do |name, model| # TODO: provide list of composee attributes in Composition.
|
42
|
-
part_properties =
|
42
|
+
part_properties = schema.find_all { |dfn| dfn[:on] == name }.collect{ |dfn| dfn[:name].to_sym }
|
43
43
|
hash[name] = self.class.nested_hash_representer.new(self).to_hash(include: part_properties)
|
44
44
|
end
|
45
45
|
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class Disposable::Twin
|
2
|
+
class Definition < Declarative::Definitions::Definition
|
3
|
+
def getter
|
4
|
+
self[:name]
|
5
|
+
end
|
6
|
+
|
7
|
+
def setter
|
8
|
+
"#{self[:name]}="
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module DefinitionsEach
|
13
|
+
def each(options={})
|
14
|
+
return self unless block_given?
|
15
|
+
|
16
|
+
super() do |dfn|
|
17
|
+
next if options[:exclude] and options[:exclude].include?(dfn[:name])
|
18
|
+
next if options[:scalar] and dfn[:collection]
|
19
|
+
next if options[:collection] and ! dfn[:collection]
|
20
|
+
next if options[:twin] and ! dfn[:nested]
|
21
|
+
|
22
|
+
yield dfn
|
23
|
+
end
|
24
|
+
|
25
|
+
self
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -24,8 +24,8 @@ module Disposable
|
|
24
24
|
|
25
25
|
def setup_property!(dfn, options)
|
26
26
|
value =
|
27
|
-
if options.has_key?(name = dfn
|
28
|
-
options[dfn
|
27
|
+
if options.has_key?(name = dfn[:name].to_sym)
|
28
|
+
options[dfn[:name].to_sym]
|
29
29
|
else
|
30
30
|
setup_value_for(dfn, options)
|
31
31
|
end
|
@@ -39,17 +39,18 @@ module Disposable
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def read_value_for(dfn, options)
|
42
|
-
mapper.send(dfn
|
42
|
+
mapper.send(dfn[:name]) # model.title.
|
43
43
|
end
|
44
44
|
|
45
45
|
def setup_write!(dfn, value)
|
46
|
-
send(dfn.setter, value)
|
46
|
+
# send(dfn.setter, value)
|
47
|
+
send("#{dfn[:name]}=", value) # FIXME!
|
47
48
|
end
|
48
49
|
|
49
50
|
# Including this will _not_ use the property's setter in Setup and allow you to override it.
|
50
51
|
module SkipSetter
|
51
52
|
def setup_write!(dfn, value)
|
52
|
-
write_property(dfn
|
53
|
+
write_property(dfn[:name], value, dfn)
|
53
54
|
end
|
54
55
|
end
|
55
56
|
end # Setup
|
@@ -5,7 +5,7 @@
|
|
5
5
|
# Twin.new(id: 1)
|
6
6
|
module Struct
|
7
7
|
def read_value_for(dfn, options)
|
8
|
-
name = dfn
|
8
|
+
name = dfn[:name]
|
9
9
|
@model[name.to_s] || @model[name.to_sym] # TODO: test sym vs. str.
|
10
10
|
end
|
11
11
|
|
@@ -15,7 +15,7 @@
|
|
15
15
|
prepare: lambda { |model, *| model },
|
16
16
|
serialize: lambda { |model, *| model.sync! },
|
17
17
|
representable: true
|
18
|
-
) if dfn[:
|
18
|
+
) if dfn[:nested]
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
data/lib/disposable/twin/sync.rb
CHANGED
@@ -5,12 +5,23 @@
|
|
5
5
|
# Note: #sync currently implicitly saves AR objects with collections
|
6
6
|
class Disposable::Twin
|
7
7
|
module Sync
|
8
|
+
class Options < ::Hash
|
9
|
+
def exclude!(names)
|
10
|
+
excludes.push(*names)
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def excludes
|
15
|
+
self[:exclude] ||= []
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
8
19
|
# Creates a fresh copy of the internal representer and adds Representable::Hash.
|
9
20
|
# This is used wherever a hash transformation is needed.
|
10
21
|
def self.hash_representer(twin_class, &block)
|
11
|
-
|
22
|
+
Disposable::Rescheme.from(twin_class,
|
12
23
|
recursive: false,
|
13
|
-
|
24
|
+
definitions_from: lambda { |twin_class| twin_class.definitions },
|
14
25
|
superclass: Representable::Decorator,
|
15
26
|
include: Representable::Hash,
|
16
27
|
exclude_options: [:default], # TODO: TEST IN default_test.
|
@@ -25,19 +36,16 @@ class Disposable::Twin
|
|
25
36
|
end
|
26
37
|
alias_method :sync, :sync_models
|
27
38
|
|
28
|
-
# reading from fields allows using readers in form for presentation
|
29
|
-
# and writers still pass to fields in #validate????
|
30
|
-
|
31
39
|
# Sync all scalar attributes, call sync! on nested and return model.
|
32
40
|
def sync!(options) # semi-public.
|
33
41
|
# TODO: merge this into Sync::Run or something and use in Struct, too, so we don't
|
34
42
|
# need the representer anymore?
|
35
|
-
options_for_sync = sync_options(
|
43
|
+
options_for_sync = sync_options(Options[options])
|
36
44
|
|
37
45
|
schema.each(options_for_sync) do |dfn|
|
38
46
|
property_value = sync_read(dfn) #
|
39
47
|
|
40
|
-
unless dfn[:
|
48
|
+
unless dfn[:nested]
|
41
49
|
mapper.send(dfn.setter, property_value) # always sync the property
|
42
50
|
next
|
43
51
|
end
|
@@ -61,6 +69,7 @@ class Disposable::Twin
|
|
61
69
|
send(definition.getter)
|
62
70
|
end
|
63
71
|
|
72
|
+
# TODO: simplify that using a decent pipeline from Representable.
|
64
73
|
module ToNestedHash
|
65
74
|
def to_nested_hash(*)
|
66
75
|
self.class.nested_hash_representer.new(nested_hash_source).to_hash
|
@@ -86,7 +95,7 @@ class Disposable::Twin
|
|
86
95
|
dfn.merge!(
|
87
96
|
prepare: lambda { |model, *| model }, # TODO: why do we need that here?
|
88
97
|
serialize: lambda { |form, args| form.to_nested_hash },
|
89
|
-
) if dfn[:
|
98
|
+
) if dfn[:nested]
|
90
99
|
end
|
91
100
|
end # #build_nested_hash_representer
|
92
101
|
end
|
@@ -107,7 +116,7 @@ class Disposable::Twin
|
|
107
116
|
def sync_options(options)
|
108
117
|
options = super
|
109
118
|
|
110
|
-
protected_fields = schema.each.find_all { |d| d[:writeable] == false }.collect { |d| d
|
119
|
+
protected_fields = schema.each.find_all { |d| d[:writeable] == false }.collect { |d| d[:name] }
|
111
120
|
options.exclude!(protected_fields)
|
112
121
|
end
|
113
122
|
end
|
@@ -126,7 +135,7 @@ class Disposable::Twin
|
|
126
135
|
def sync_options(options)
|
127
136
|
# DISCUSS: we currently don't track if nested forms have changed (only their attributes). that's why i include them all here, which
|
128
137
|
# is additional sync work/slightly wrong. solution: allow forms to form.changed? not sure how to do that with collections.
|
129
|
-
scalars = schema.each(scalar: true).collect { |dfn| dfn
|
138
|
+
scalars = schema.each(scalar: true).collect { |dfn| dfn[:name ]}
|
130
139
|
unchanged = scalars - changed.keys
|
131
140
|
|
132
141
|
# exclude unchanged scalars, nested forms and changed scalars still go in here!
|
@@ -139,7 +148,7 @@ class Disposable::Twin
|
|
139
148
|
# Include this won't use the getter #title in #sync but read directly from @fields.
|
140
149
|
module SkipGetter
|
141
150
|
def sync_read(dfn)
|
142
|
-
@fields[dfn
|
151
|
+
@fields[dfn[:name]]
|
143
152
|
end
|
144
153
|
|
145
154
|
def nested_hash_source
|
data/lib/disposable/twin.rb
CHANGED
@@ -1,19 +1,18 @@
|
|
1
|
-
# DISCUSS: sync via @fields, not reader? allows overriding a la reform 1.
|
2
|
-
|
3
1
|
require "uber/inheritable_attr"
|
4
|
-
|
5
|
-
require "disposable/twin/
|
2
|
+
require "declarative/schema"
|
3
|
+
require "disposable/twin/definitions"
|
6
4
|
require "disposable/twin/collection"
|
7
5
|
require "disposable/twin/setup"
|
8
6
|
require "disposable/twin/sync"
|
9
7
|
require "disposable/twin/save"
|
10
|
-
require "disposable/twin/option"
|
11
8
|
require "disposable/twin/builder"
|
12
9
|
require "disposable/twin/changed"
|
13
10
|
require "disposable/twin/property_processor"
|
14
11
|
require "disposable/twin/persisted"
|
15
12
|
require "disposable/twin/default"
|
16
13
|
|
14
|
+
require "representable/decorator"
|
15
|
+
|
17
16
|
# Twin.new(model/composition hash/hash, options)
|
18
17
|
# assign hash to @fields
|
19
18
|
# write: write to @fields
|
@@ -21,29 +20,20 @@ require "disposable/twin/default"
|
|
21
20
|
|
22
21
|
module Disposable
|
23
22
|
class Twin
|
24
|
-
extend
|
25
|
-
|
26
|
-
|
27
|
-
self.representer_class = Class.new(Decorator)
|
28
|
-
|
29
|
-
# Returns an each'able array of all properties defined in this twin.
|
30
|
-
# Allows to filter using
|
31
|
-
# * collection: true
|
32
|
-
# * twin: true
|
33
|
-
# * scalar: true
|
34
|
-
# * exclude: ["title", "email"]
|
35
|
-
def schema
|
36
|
-
self.class.representer_class
|
23
|
+
extend Declarative::Schema
|
24
|
+
def self.definition_class
|
25
|
+
Definition
|
37
26
|
end
|
38
27
|
|
39
|
-
|
40
|
-
|
41
|
-
def self.register_feature(mod)
|
42
|
-
representer_class.representable_attrs[:features][mod] = true
|
28
|
+
def schema
|
29
|
+
self.class.definitions.extend(DefinitionsEach)
|
43
30
|
end
|
44
31
|
|
45
|
-
|
46
32
|
class << self
|
33
|
+
def default_nested_class
|
34
|
+
Twin
|
35
|
+
end
|
36
|
+
|
47
37
|
# TODO: move to Declarative, as in Representable and Reform.
|
48
38
|
def property(name, options={}, &block)
|
49
39
|
options[:private_name] = options.delete(:from) || name
|
@@ -52,18 +42,10 @@ module Disposable
|
|
52
42
|
options[:writeable] = options[:readable] = false
|
53
43
|
end
|
54
44
|
|
55
|
-
options[:
|
45
|
+
options[:nested] = options.delete(:twin) if options[:twin]
|
56
46
|
|
57
|
-
|
47
|
+
super(name, options, &block).tap do |definition|
|
58
48
|
create_accessors(name, definition)
|
59
|
-
|
60
|
-
if definition[:extend] and !options[:twin]
|
61
|
-
# This will soon be replaced with Declarative's API. # DISCUSS: could we use build_inline's api here to inject the name feature?
|
62
|
-
nested_twin = definition[:extend].evaluate(nil)
|
63
|
-
process_inline!(nested_twin, definition)
|
64
|
-
|
65
|
-
definition.merge!(twin: nested_twin) # DISCUSS: where do we need this?
|
66
|
-
end
|
67
49
|
end
|
68
50
|
end
|
69
51
|
|
@@ -80,14 +62,10 @@ module Disposable
|
|
80
62
|
mod = Module.new do
|
81
63
|
define_method(name) { @fields[name.to_s] }
|
82
64
|
# define_method(name) { read_property(name) }
|
83
|
-
define_method("#{name}=") { |value| write_property(name, value, definition) }
|
65
|
+
define_method("#{name}=") { |value| write_property(name, value, definition) }
|
84
66
|
end
|
85
67
|
include mod
|
86
68
|
end
|
87
|
-
|
88
|
-
# DISCUSS: this method might disappear or change pretty soon.
|
89
|
-
def process_inline!(mod, definition)
|
90
|
-
end
|
91
69
|
end
|
92
70
|
|
93
71
|
include Setup
|
@@ -97,8 +75,8 @@ module Disposable
|
|
97
75
|
private
|
98
76
|
# assumption: collections are always initialized from Setup since we assume an empty [] for "nil"/uninitialized collections.
|
99
77
|
def write_property(name, value, dfn)
|
100
|
-
if dfn[:
|
101
|
-
value = dfn
|
78
|
+
if dfn[:nested] and value
|
79
|
+
value = dfn[:collection] ? wrap_collection(dfn, value) : wrap_scalar(dfn, value)
|
102
80
|
end
|
103
81
|
|
104
82
|
field_write(name, value)
|
@@ -124,24 +102,13 @@ module Disposable
|
|
124
102
|
end
|
125
103
|
include Accessors
|
126
104
|
|
127
|
-
|
128
|
-
# FIXME: this is experimental.
|
129
|
-
module ToS
|
130
|
-
def to_s
|
131
|
-
return super if self.class.name
|
132
|
-
"#<Twin (inline):#{object_id}>"
|
133
|
-
end
|
134
|
-
end
|
135
|
-
include ToS
|
136
|
-
|
137
|
-
|
138
105
|
class Twinner
|
139
106
|
def initialize(dfn)
|
140
107
|
@dfn = dfn
|
141
108
|
end
|
142
109
|
|
143
110
|
def call(value)
|
144
|
-
@dfn.
|
111
|
+
@dfn[:nested].new(value)
|
145
112
|
end
|
146
113
|
end
|
147
114
|
|
@@ -152,7 +119,5 @@ module Disposable
|
|
152
119
|
attr_reader :mapper
|
153
120
|
end
|
154
121
|
include ModelReaders
|
155
|
-
|
156
|
-
include Option
|
157
122
|
end
|
158
|
-
end
|
123
|
+
end
|
data/lib/disposable/version.rb
CHANGED
data/lib/disposable.rb
CHANGED
data/test/callback_group_test.rb
CHANGED
@@ -148,10 +148,10 @@ class CallbackGroupInheritanceTest < MiniTest::Spec
|
|
148
148
|
it do
|
149
149
|
Group.hooks.size.must_equal 4
|
150
150
|
Group.hooks[0].to_s.must_equal "[:on_change, [:change!]]"
|
151
|
-
# Group.hooks[1][1].
|
151
|
+
# Group.hooks[1][1][:nested].hooks.to_s.must_equal "[[:on_add, [:notify_album!]],[:on_add, [:reset_song!]]]"
|
152
152
|
Group.hooks[2].to_s.must_equal "[:on_change, [:rehash_name!, {:property=>:title}]]"
|
153
153
|
|
154
|
-
Group.
|
154
|
+
Group.definitions.get(Group.hooks[3][1])[:nested].hooks.to_s.must_equal "[[:on_change, [:sing!]]]"
|
155
155
|
end
|
156
156
|
|
157
157
|
class EmptyGroup < Group
|
@@ -173,8 +173,9 @@ class CallbackGroupInheritanceTest < MiniTest::Spec
|
|
173
173
|
|
174
174
|
it do
|
175
175
|
Group.hooks.size.must_equal 4
|
176
|
+
pp EnhancedGroup.hooks
|
176
177
|
EnhancedGroup.hooks.size.must_equal 6
|
177
|
-
EnhancedGroup.
|
178
|
+
EnhancedGroup.definitions.get(EnhancedGroup.hooks[5][1])[:nested].hooks.to_s.must_equal "[[:on_add, [:rewind!]]]"
|
178
179
|
end
|
179
180
|
|
180
181
|
class EnhancedWithInheritGroup < EnhancedGroup
|
@@ -190,10 +191,10 @@ class CallbackGroupInheritanceTest < MiniTest::Spec
|
|
190
191
|
Group.hooks.size.must_equal 4
|
191
192
|
EnhancedGroup.hooks.size.must_equal 6
|
192
193
|
|
193
|
-
EnhancedGroup.
|
194
|
+
EnhancedGroup.definitions.get(EnhancedGroup.hooks[5][1])[:nested].hooks.to_s.must_equal "[[:on_add, [:rewind!]]]"
|
194
195
|
EnhancedWithInheritGroup.hooks.size.must_equal 6
|
195
|
-
EnhancedWithInheritGroup.
|
196
|
-
EnhancedWithInheritGroup.
|
196
|
+
EnhancedWithInheritGroup.definitions.get(EnhancedWithInheritGroup.hooks[1][1])[:nested].hooks.to_s.must_equal "[[:on_add, [:rewind!]], [:on_add, [:eat!]]]"
|
197
|
+
EnhancedWithInheritGroup.definitions.get(EnhancedWithInheritGroup.hooks[3][1])[:nested].hooks.to_s.must_equal "[[:on_change, [:sing!]], [:on_delete, [:yell!]]]"
|
197
198
|
end
|
198
199
|
|
199
200
|
class RemovingInheritGroup < Group
|
@@ -205,19 +206,19 @@ class CallbackGroupInheritanceTest < MiniTest::Spec
|
|
205
206
|
|
206
207
|
# # puts "@@@@@ #{Group.hooks.object_id.inspect}"
|
207
208
|
# # puts "@@@@@ #{EmptyGroup.hooks.object_id.inspect}"
|
208
|
-
# puts "@@@@@ Group: #{Group.
|
209
|
-
# puts "@@@@@ EnhancedGroup: #{EnhancedGroup.
|
210
|
-
# puts "@@@@@ InheritGroup: #{EnhancedWithInheritGroup.
|
211
|
-
# puts "@@@@@ RemovingGroup: #{RemovingInheritGroup.
|
212
|
-
# # puts "@@@@@ #{EnhancedWithInheritGroup.
|
209
|
+
# puts "@@@@@ Group: #{Group.definitions.get(:songs)[:nested].hooks.inspect}"
|
210
|
+
# puts "@@@@@ EnhancedGroup: #{EnhancedGroup.definitions.get(:songs)[:nested].hooks.inspect}"
|
211
|
+
# puts "@@@@@ InheritGroup: #{EnhancedWithInheritGroup.definitions.get(:songs)[:nested].hooks.inspect}"
|
212
|
+
# puts "@@@@@ RemovingGroup: #{RemovingInheritGroup.definitions.get(:songs)[:nested].hooks.inspect}"
|
213
|
+
# # puts "@@@@@ #{EnhancedWithInheritGroup.definitions.get(:songs)[:nested].hooks.object_id.inspect}"
|
213
214
|
|
214
215
|
# TODO: object_id tests for all nested representers.
|
215
216
|
|
216
217
|
it do
|
217
218
|
Group.hooks.size.must_equal 4
|
218
219
|
RemovingInheritGroup.hooks.size.must_equal 3
|
219
|
-
RemovingInheritGroup.
|
220
|
-
RemovingInheritGroup.
|
220
|
+
RemovingInheritGroup.definitions.get(RemovingInheritGroup.hooks[0][1])[:nested].hooks.to_s.must_equal "[[:on_add, [:reset_song!]]]"
|
221
|
+
RemovingInheritGroup.definitions.get(RemovingInheritGroup.hooks[2][1])[:nested].hooks.to_s.must_equal "[[:on_change, [:sing!]]]"
|
221
222
|
end
|
222
223
|
|
223
224
|
# Group::clone
|
data/test/expose_test.rb
CHANGED
@@ -16,7 +16,7 @@ class ExposeTest < MiniTest::Spec
|
|
16
16
|
end
|
17
17
|
|
18
18
|
class AlbumExpose < Disposable::Expose
|
19
|
-
from Twin::Album.
|
19
|
+
from Twin::Album.definitions.values
|
20
20
|
end
|
21
21
|
|
22
22
|
let (:album) { Model::Album.new(1, "Dick Sandwich") }
|
@@ -59,7 +59,7 @@ class ExposeCompositionTest < MiniTest::Spec
|
|
59
59
|
end
|
60
60
|
|
61
61
|
class AlbumComposition < Disposable::Composition
|
62
|
-
from Twin::Album.
|
62
|
+
from Twin::Album.definitions.values
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
@@ -1,8 +1,6 @@
|
|
1
1
|
require "test_helper"
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
class SchemaTest < MiniTest::Spec
|
3
|
+
class ReschemeTest < MiniTest::Spec
|
6
4
|
module Representer
|
7
5
|
include Representable
|
8
6
|
|
@@ -32,80 +30,80 @@ class SchemaTest < MiniTest::Spec
|
|
32
30
|
end
|
33
31
|
|
34
32
|
it do
|
35
|
-
decorator = Disposable::
|
36
|
-
include: [Hello, Gday, Ciao], # Hello will win over Gday.
|
33
|
+
decorator = Disposable::Rescheme.from(Representer, superclass: Representable::Decorator,
|
34
|
+
include: [Representable::Hash, Hello, Gday, Ciao], # Hello will win over Gday.
|
37
35
|
options_from: :deserializer,
|
38
|
-
|
36
|
+
definitions_from: lambda { |nested| nested.definitions }
|
39
37
|
)
|
40
38
|
|
41
39
|
# include: works.
|
42
40
|
decorator.new(nil).hello.must_equal "hello"
|
43
41
|
decorator.new(nil).ciao.must_equal "ciao"
|
44
42
|
|
45
|
-
decorator.representable_attrs.get(:id).inspect.must_equal "#<Representable::Definition ==>id @options={:parse_filter=>[], :render_filter=>[]
|
46
|
-
decorator.representable_attrs.get(:title).inspect.must_equal "#<Representable::Definition ==>title @options={:writeable=>false, :deserializer=>{:skip_parse=>\"skip lambda\"}, :parse_filter=>[], :render_filter=>[], :
|
43
|
+
decorator.representable_attrs.get(:id).inspect.must_equal "#<Representable::Definition ==>id @options={:name=>\"id\", :parse_filter=>[], :render_filter=>[]}>"
|
44
|
+
decorator.representable_attrs.get(:title).inspect.must_equal "#<Representable::Definition ==>title @options={:writeable=>false, :deserializer=>{:skip_parse=>\"skip lambda\"}, :name=>\"title\", :parse_filter=>[], :render_filter=>[], :skip_parse=>\"skip lambda\"}>"
|
47
45
|
|
48
46
|
songs = decorator.representable_attrs.get(:songs)
|
49
47
|
options = songs.instance_variable_get(:@options)
|
50
|
-
|
51
|
-
options.inspect.must_equal "{:readable=>false, :deserializer=>{:skip_parse=>\"another lambda\", :music=>true, :writeable=>false}, :
|
48
|
+
options[:nested].extend(Declarative::Inspect)
|
49
|
+
options.inspect.must_equal "{:readable=>false, :deserializer=>{:skip_parse=>\"another lambda\", :music=>true, :writeable=>false}, :nested=>#<Class:>, :extend=>#<Class:>, :name=>\"songs\", :parse_filter=>[], :render_filter=>[], :skip_parse=>\"another lambda\", :music=>true, :writeable=>false}"
|
52
50
|
|
53
51
|
# nested works.
|
54
|
-
|
55
|
-
|
52
|
+
options[:nested].new(nil).hello.must_equal "hello"
|
53
|
+
options[:nested].new(nil).ciao.must_equal "ciao"
|
56
54
|
|
57
|
-
|
55
|
+
options[:nested].representable_attrs.get(:name).inspect.must_equal "#<Representable::Definition ==>name @options={:as=>\"Name\", :deserializer=>{:skip_parse=>\"a crazy cool instance method\"}, :name=>\"name\", :parse_filter=>[], :render_filter=>[], :skip_parse=>\"a crazy cool instance method\"}>"
|
58
56
|
end
|
59
57
|
|
60
58
|
# :options_from and :include is optional
|
61
59
|
it do
|
62
|
-
decorator = Disposable::
|
63
|
-
|
60
|
+
decorator = Disposable::Rescheme.from(Representer, superclass: Representable::Decorator, include: [Representable::Hash],
|
61
|
+
definitions_from: lambda { |nested| nested.definitions }
|
64
62
|
)
|
65
63
|
|
66
|
-
decorator.representable_attrs.get(:id).inspect.must_equal "#<Representable::Definition ==>id @options={:parse_filter=>[], :render_filter=>[]
|
67
|
-
decorator.representable_attrs.get(:title).inspect.must_equal "#<Representable::Definition ==>title @options={:writeable=>false, :deserializer=>{:skip_parse=>\"skip lambda\"}, :parse_filter=>[], :render_filter=>[]
|
64
|
+
decorator.representable_attrs.get(:id).inspect.must_equal "#<Representable::Definition ==>id @options={:name=>\"id\", :parse_filter=>[], :render_filter=>[]}>"
|
65
|
+
decorator.representable_attrs.get(:title).inspect.must_equal "#<Representable::Definition ==>title @options={:writeable=>false, :deserializer=>{:skip_parse=>\"skip lambda\"}, :name=>\"title\", :parse_filter=>[], :render_filter=>[]}>"
|
68
66
|
end
|
69
67
|
|
70
68
|
|
71
69
|
# :exclude_options allows skipping particular options when copying.
|
72
70
|
it do
|
73
|
-
decorator = Disposable::
|
74
|
-
|
71
|
+
decorator = Disposable::Rescheme.from(Representer, superclass: Representable::Decorator, include: [Representable::Hash],
|
72
|
+
definitions_from: lambda { |nested| nested.definitions },
|
75
73
|
exclude_options: [:deserializer]
|
76
74
|
)
|
77
75
|
|
78
|
-
decorator.representable_attrs.get(:id).inspect.must_equal "#<Representable::Definition ==>id @options={:parse_filter=>[], :render_filter=>[]
|
79
|
-
decorator.representable_attrs.get(:title).inspect.must_equal "#<Representable::Definition ==>title @options={:writeable=>false, :parse_filter=>[], :render_filter=>[]
|
80
|
-
decorator.representable_attrs.get(:songs).representer_module.representable_attrs.get(:name).inspect.must_equal "#<Representable::Definition ==>name @options={:as=>\"Name\", :parse_filter=>[], :render_filter=>[]}>"
|
76
|
+
decorator.representable_attrs.get(:id).inspect.must_equal "#<Representable::Definition ==>id @options={:name=>\"id\", :parse_filter=>[], :render_filter=>[]}>"
|
77
|
+
decorator.representable_attrs.get(:title).inspect.must_equal "#<Representable::Definition ==>title @options={:writeable=>false, :name=>\"title\", :parse_filter=>[], :render_filter=>[]}>"
|
78
|
+
decorator.representable_attrs.get(:songs).representer_module.representable_attrs.get(:name).inspect.must_equal "#<Representable::Definition ==>name @options={:as=>\"Name\", :name=>\"name\", :parse_filter=>[], :render_filter=>[]}>"
|
81
79
|
end
|
82
80
|
|
83
81
|
|
84
82
|
it "::from with block allows customizing every definition and returns representer" do
|
85
|
-
decorator = Disposable::
|
83
|
+
decorator = Disposable::Rescheme.from(Representer, include: [Representable::Hash],
|
86
84
|
superclass: Representable::Decorator,
|
87
|
-
|
85
|
+
definitions_from: lambda { |nested| nested.definitions },
|
88
86
|
) { |dfn| dfn.merge!(amazing: true) }
|
89
87
|
|
90
|
-
decorator.representable_attrs.get(:id).inspect.must_equal "#<Representable::Definition ==>id @options={:parse_filter=>[], :render_filter=>[], :
|
91
|
-
decorator.representable_attrs.get(:songs).representer_module.representable_attrs.get(:name).inspect.must_equal "#<Representable::Definition ==>name @options={:as=>\"Name\", :deserializer=>{:skip_parse=>\"a crazy cool instance method\"}, :parse_filter=>[], :render_filter=>[], :amazing=>true}>"
|
88
|
+
decorator.representable_attrs.get(:id).inspect.must_equal "#<Representable::Definition ==>id @options={:name=>\"id\", :parse_filter=>[], :render_filter=>[], :amazing=>true}>"
|
89
|
+
decorator.representable_attrs.get(:songs).representer_module.representable_attrs.get(:name).inspect.must_equal "#<Representable::Definition ==>name @options={:as=>\"Name\", :deserializer=>{:skip_parse=>\"a crazy cool instance method\"}, :name=>\"name\", :parse_filter=>[], :render_filter=>[], :amazing=>true}>"
|
92
90
|
end
|
93
91
|
|
94
92
|
it "recursive: false only copies first level" do
|
95
|
-
decorator = Disposable::
|
93
|
+
decorator = Disposable::Rescheme.from(Representer, include: [Representable::Hash],
|
96
94
|
superclass: Representable::Decorator,
|
97
|
-
|
95
|
+
definitions_from: lambda { |nested| nested.definitions },
|
98
96
|
recursive: false,
|
99
97
|
exclude_options: [:deserializer]
|
100
98
|
)
|
101
99
|
|
102
|
-
decorator.representable_attrs.get(:title).inspect.must_equal "#<Representable::Definition ==>title @options={:writeable=>false, :parse_filter=>[], :render_filter=>[]
|
103
|
-
decorator.representable_attrs.get(:songs).representer_module.representable_attrs.get(:name).inspect.must_equal "#<Representable::Definition ==>name @options={:as=>\"Name\", :deserializer=>{:skip_parse=>\"a crazy cool instance method\"}, :parse_filter=>[], :render_filter=>[]}>"
|
100
|
+
decorator.representable_attrs.get(:title).inspect.must_equal "#<Representable::Definition ==>title @options={:writeable=>false, :name=>\"title\", :parse_filter=>[], :render_filter=>[]}>"
|
101
|
+
decorator.representable_attrs.get(:songs).representer_module.representable_attrs.get(:name).inspect.must_equal "#<Representable::Definition ==>name @options={:as=>\"Name\", :deserializer=>{:skip_parse=>\"a crazy cool instance method\"}, :name=>\"name\", :parse_filter=>[], :render_filter=>[]}>"
|
104
102
|
end
|
105
103
|
end
|
106
104
|
|
107
105
|
|
108
|
-
class
|
106
|
+
class TwinReschemeTest < MiniTest::Spec
|
109
107
|
class Artist < Disposable::Twin
|
110
108
|
property :name
|
111
109
|
end
|
@@ -115,15 +113,15 @@ class TwinSchemaTest < MiniTest::Spec
|
|
115
113
|
end
|
116
114
|
|
117
115
|
it do
|
118
|
-
decorator = Disposable::
|
119
|
-
|
116
|
+
decorator = Disposable::Rescheme.from(Album, superclass: Representable::Decorator, include: [Representable::Hash],
|
117
|
+
definitions_from: lambda { |nested| nested.definitions }
|
120
118
|
)
|
121
119
|
|
122
120
|
artist = decorator.representable_attrs.get(:artist)
|
123
121
|
options = artist.instance_variable_get(:@options)
|
124
|
-
nested_extend = options
|
125
|
-
options.inspect.must_equal "{:
|
122
|
+
nested_extend = options[:nested]
|
123
|
+
options.extend(Declarative::Inspect).inspect.must_equal "{:private_name=>:artist, :nested=>#<Class:>, :name=>\"artist\", :extend=>#<Class:>, :parse_filter=>[], :render_filter=>[]}"
|
126
124
|
assert nested_extend < Representable::Decorator
|
127
|
-
nested_extend.representable_attrs.get(:name).inspect.must_equal "#<Representable::Definition ==>name @options={:private_name=>:name, :parse_filter=>[], :render_filter=>[]
|
125
|
+
nested_extend.representable_attrs.get(:name).inspect.must_equal "#<Representable::Definition ==>name @options={:private_name=>:name, :name=>\"name\", :parse_filter=>[], :render_filter=>[]}>"
|
128
126
|
end
|
129
127
|
end
|
data/test/test_helper.rb
CHANGED
@@ -16,13 +16,13 @@ class TwinCollectionTest < MiniTest::Spec
|
|
16
16
|
class Song < Disposable::Twin
|
17
17
|
property :id # DISCUSS: needed for #save.
|
18
18
|
property :title
|
19
|
-
property :album, :
|
19
|
+
# property :album, twin: Album
|
20
20
|
end
|
21
21
|
|
22
22
|
class Album < Disposable::Twin
|
23
23
|
property :id # DISCUSS: needed for #save.
|
24
24
|
property :name
|
25
|
-
collection :songs, :
|
25
|
+
collection :songs, twin: Song
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -62,8 +62,8 @@ class TwinCollectionActiveRecordTest < MiniTest::Spec
|
|
62
62
|
class Album < Disposable::Twin
|
63
63
|
property :id # DISCUSS: needed for #save.
|
64
64
|
property :name
|
65
|
-
collection :songs, :
|
66
|
-
property :artist, twin:
|
65
|
+
collection :songs, twin: Twin::Song
|
66
|
+
property :artist, twin: Twin::Artist
|
67
67
|
|
68
68
|
include Sync
|
69
69
|
include Save
|
@@ -208,7 +208,7 @@ class CollectionUnitTest < MiniTest::Spec
|
|
208
208
|
Album = Struct.new(:id, :name, :songs, :artist)
|
209
209
|
end
|
210
210
|
|
211
|
-
let(:collection) { Disposable::Twin::Collection.new(Disposable::Twin::Twinner.new(Twin::Song.
|
211
|
+
let(:collection) { Disposable::Twin::Collection.new(Disposable::Twin::Twinner.new(Twin::Song.definitions.get(:album)), []) }
|
212
212
|
|
213
213
|
# #insert(index, model)
|
214
214
|
it do
|
data/test/twin/feature_test.rb
CHANGED
@@ -18,23 +18,19 @@ class FeatureTest < MiniTest::Spec
|
|
18
18
|
end
|
19
19
|
|
20
20
|
class AlbumForm < Disposable::Twin
|
21
|
-
include Setup
|
22
21
|
feature Date
|
23
22
|
property :name
|
24
23
|
|
25
24
|
collection :songs do
|
26
|
-
include Setup
|
27
25
|
property :title
|
28
26
|
|
29
27
|
property :composer do
|
30
|
-
include Setup
|
31
28
|
feature Instrument
|
32
29
|
property :name
|
33
30
|
end
|
34
31
|
end
|
35
32
|
|
36
33
|
property :artist do
|
37
|
-
include Setup
|
38
34
|
property :name
|
39
35
|
end
|
40
36
|
end
|
data/test/twin/inherit_test.rb
CHANGED
@@ -40,8 +40,8 @@ class InheritTest < MiniTest::Spec
|
|
40
40
|
|
41
41
|
# definitions are not shared.
|
42
42
|
it do
|
43
|
-
Twin::Album.
|
44
|
-
Twin::Compilation.
|
43
|
+
Twin::Album.definitions.get(:name).extend(Declarative::Inspect).inspect.must_equal "#<Disposable::Twin::Definition: @options={:fromage=>:_name, :private_name=>:name, :name=>\"name\"}>"
|
44
|
+
Twin::Compilation.definitions.get(:name).extend(Declarative::Inspect).inspect.must_equal "#<Disposable::Twin::Definition: @options={:fromage=>:_name, :private_name=>:name, :name=>\"name\", :writeable=>false}>" # FIXME: where did :inherit go?
|
45
45
|
end
|
46
46
|
|
47
47
|
|
@@ -1,35 +1,35 @@
|
|
1
|
-
require "test_helper"
|
1
|
+
# require "test_helper"
|
2
2
|
|
3
|
-
class ProcessInlineTest < MiniTest::Spec
|
4
|
-
|
3
|
+
# class ProcessInlineTest < MiniTest::Spec
|
4
|
+
# Album = Struct.new(:artist, :composer, :recursive_composer)
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
# module InlineTwin
|
7
|
+
# end
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
# class RecursiveComposerTwin < Disposable::Twin
|
10
|
+
# property :composer, twin: self
|
11
|
+
# end
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
# class AlbumTwin < Disposable::Twin
|
14
|
+
# def self.process_inline!(inline_class, definition)
|
15
|
+
# inline_class.send :include, InlineTwin
|
16
|
+
# end
|
17
17
|
|
18
|
-
|
19
|
-
|
18
|
+
# property :artist do
|
19
|
+
# end
|
20
20
|
|
21
|
-
|
21
|
+
# property :composer, twin: ->{ ComposerTwin }
|
22
22
|
|
23
|
-
|
24
|
-
|
23
|
+
# property :recursive_composer, twin: RecursiveComposerTwin
|
24
|
+
# end
|
25
25
|
|
26
|
-
|
27
|
-
|
26
|
+
# class ComposerTwin < Disposable::Twin
|
27
|
+
# end
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
29
|
+
# it do
|
30
|
+
# twin = AlbumTwin.new(Album.new(Object, Object))
|
31
|
+
# assert ! (twin.class < InlineTwin)
|
32
|
+
# assert (twin.artist.class < InlineTwin)
|
33
|
+
# assert ! (twin.composer.class < InlineTwin)
|
34
|
+
# end
|
35
|
+
# end
|
data/test/twin/setup_test.rb
CHANGED
@@ -17,7 +17,7 @@ class TwinSetupTest < MiniTest::Spec
|
|
17
17
|
|
18
18
|
class Song < Disposable::Twin
|
19
19
|
property :id
|
20
|
-
property :composer, twin:
|
20
|
+
property :composer, twin: Twin::Artist
|
21
21
|
|
22
22
|
include Setup
|
23
23
|
end
|
@@ -25,8 +25,8 @@ class TwinSetupTest < MiniTest::Spec
|
|
25
25
|
class Album < Disposable::Twin
|
26
26
|
property :id
|
27
27
|
property :name
|
28
|
-
collection :songs, twin:
|
29
|
-
property :artist, twin:
|
28
|
+
collection :songs, twin: Twin::Song
|
29
|
+
property :artist, twin: Twin::Artist
|
30
30
|
|
31
31
|
include Setup
|
32
32
|
end
|
data/test/twin/twin_test.rb
CHANGED
@@ -7,25 +7,24 @@ class TwinTest < MiniTest::Spec
|
|
7
7
|
Artist = Struct.new(:id)
|
8
8
|
end
|
9
9
|
|
10
|
-
|
10
|
+
# test twin: option
|
11
11
|
module Twin
|
12
|
+
class Artist < Disposable::Twin
|
13
|
+
property :id
|
14
|
+
|
15
|
+
include Setup
|
16
|
+
end
|
17
|
+
|
12
18
|
class Album < Disposable::Twin
|
13
19
|
property :id # DISCUSS: needed for #save.
|
14
20
|
property :name
|
15
|
-
|
16
|
-
property :artist, :twin => lambda { |*| Artist }
|
21
|
+
property :artist, twin: Artist
|
17
22
|
end
|
18
23
|
|
19
24
|
class Song < Disposable::Twin
|
20
25
|
property :id # DISCUSS: needed for #save.
|
21
26
|
property :title
|
22
|
-
property :album, :
|
23
|
-
end
|
24
|
-
|
25
|
-
class Artist < Disposable::Twin
|
26
|
-
property :id
|
27
|
-
|
28
|
-
include Setup
|
27
|
+
property :album, twin: Album
|
29
28
|
end
|
30
29
|
end
|
31
30
|
|
@@ -91,20 +90,6 @@ class TwinTest < MiniTest::Spec
|
|
91
90
|
# result.must_equal twin.album
|
92
91
|
# end
|
93
92
|
end
|
94
|
-
|
95
|
-
# FIXME: experimental.
|
96
|
-
describe "#to_s" do
|
97
|
-
class HitTwin < Disposable::Twin
|
98
|
-
include Setup
|
99
|
-
|
100
|
-
property :song do
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
let (:hit) { OpenStruct.new(song: song) }
|
105
|
-
it { HitTwin.new(hit).to_s.must_match "#<TwinTest::HitTwin:" }
|
106
|
-
it { HitTwin.new(hit).song.to_s.must_match "#<Twin (inline):" }
|
107
|
-
end
|
108
93
|
end
|
109
94
|
|
110
95
|
|
@@ -138,7 +123,7 @@ class TwinAsTest < MiniTest::Spec
|
|
138
123
|
|
139
124
|
class Song < Disposable::Twin
|
140
125
|
property :name, :from => :title
|
141
|
-
property :record, :
|
126
|
+
property :record, twin: Album, :from => :album
|
142
127
|
|
143
128
|
# model Model::Song
|
144
129
|
end
|
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
|
+
version: 0.2.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Sutterer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-11-
|
11
|
+
date: 2015-11-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: uber
|
@@ -24,26 +24,40 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: declarative
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.0.4
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.0.4
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: representable
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
45
|
- - ">="
|
32
46
|
- !ruby/object:Gem::Version
|
33
|
-
version: 2.
|
47
|
+
version: 2.4.0.rc1
|
34
48
|
- - "<"
|
35
49
|
- !ruby/object:Gem::Version
|
36
|
-
version: 2.
|
50
|
+
version: 2.5.0
|
37
51
|
type: :runtime
|
38
52
|
prerelease: false
|
39
53
|
version_requirements: !ruby/object:Gem::Requirement
|
40
54
|
requirements:
|
41
55
|
- - ">="
|
42
56
|
- !ruby/object:Gem::Version
|
43
|
-
version: 2.
|
57
|
+
version: 2.4.0.rc1
|
44
58
|
- - "<"
|
45
59
|
- !ruby/object:Gem::Version
|
46
|
-
version: 2.
|
60
|
+
version: 2.5.0
|
47
61
|
- !ruby/object:Gem::Dependency
|
48
62
|
name: bundler
|
49
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -152,6 +166,7 @@ files:
|
|
152
166
|
- lib/disposable/callback.rb
|
153
167
|
- lib/disposable/composition.rb
|
154
168
|
- lib/disposable/expose.rb
|
169
|
+
- lib/disposable/rescheme.rb
|
155
170
|
- lib/disposable/twin.rb
|
156
171
|
- lib/disposable/twin/builder.rb
|
157
172
|
- lib/disposable/twin/changed.rb
|
@@ -159,12 +174,10 @@ files:
|
|
159
174
|
- lib/disposable/twin/collection.rb
|
160
175
|
- lib/disposable/twin/composition.rb
|
161
176
|
- lib/disposable/twin/default.rb
|
162
|
-
- lib/disposable/twin/
|
177
|
+
- lib/disposable/twin/definitions.rb
|
163
178
|
- lib/disposable/twin/persisted.rb
|
164
179
|
- lib/disposable/twin/property_processor.rb
|
165
|
-
- lib/disposable/twin/representer.rb
|
166
180
|
- lib/disposable/twin/save.rb
|
167
|
-
- lib/disposable/twin/schema.rb
|
168
181
|
- lib/disposable/twin/setup.rb
|
169
182
|
- lib/disposable/twin/struct.rb
|
170
183
|
- lib/disposable/twin/sync.rb
|
@@ -175,6 +188,7 @@ files:
|
|
175
188
|
- test/example.rb
|
176
189
|
- test/expose_test.rb
|
177
190
|
- test/persisted_test.rb
|
191
|
+
- test/rescheme_test.rb
|
178
192
|
- test/skip_getter_test.rb
|
179
193
|
- test/test_helper.rb
|
180
194
|
- test/twin/benchmarking.rb
|
@@ -193,7 +207,6 @@ files:
|
|
193
207
|
- test/twin/process_inline_test.rb
|
194
208
|
- test/twin/readable_test.rb
|
195
209
|
- test/twin/save_test.rb
|
196
|
-
- test/twin/schema_test.rb
|
197
210
|
- test/twin/setup_test.rb
|
198
211
|
- test/twin/skip_unchanged_test.rb
|
199
212
|
- test/twin/struct_test.rb
|
@@ -217,9 +230,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
217
230
|
version: '0'
|
218
231
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
219
232
|
requirements:
|
220
|
-
- - "
|
233
|
+
- - ">"
|
221
234
|
- !ruby/object:Gem::Version
|
222
|
-
version:
|
235
|
+
version: 1.3.1
|
223
236
|
requirements: []
|
224
237
|
rubyforge_project:
|
225
238
|
rubygems_version: 2.4.8
|
@@ -234,6 +247,7 @@ test_files:
|
|
234
247
|
- test/example.rb
|
235
248
|
- test/expose_test.rb
|
236
249
|
- test/persisted_test.rb
|
250
|
+
- test/rescheme_test.rb
|
237
251
|
- test/skip_getter_test.rb
|
238
252
|
- test/test_helper.rb
|
239
253
|
- test/twin/benchmarking.rb
|
@@ -252,7 +266,6 @@ test_files:
|
|
252
266
|
- test/twin/process_inline_test.rb
|
253
267
|
- test/twin/readable_test.rb
|
254
268
|
- test/twin/save_test.rb
|
255
|
-
- test/twin/schema_test.rb
|
256
269
|
- test/twin/setup_test.rb
|
257
270
|
- test/twin/skip_unchanged_test.rb
|
258
271
|
- test/twin/struct_test.rb
|
@@ -1,12 +0,0 @@
|
|
1
|
-
module Disposable::Twin::Option
|
2
|
-
def self.included(base)
|
3
|
-
base.extend ClassMethods
|
4
|
-
end
|
5
|
-
|
6
|
-
module ClassMethods
|
7
|
-
def option(name, options={})
|
8
|
-
# default: nil will always set an option in the, even when not in the incoming options.
|
9
|
-
property(name, options.merge(readable: false, writeable: false, default: nil))
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
require "representable/decorator"
|
2
|
-
# require "representable/hash"
|
3
|
-
|
4
|
-
module Disposable
|
5
|
-
class Twin
|
6
|
-
class Decorator < Representable::Decorator
|
7
|
-
# Overrides representable's Definition class so we can add semantics in our representers.
|
8
|
-
class Definition < Representable::Definition
|
9
|
-
def dynamic_options
|
10
|
-
super + [:twin]
|
11
|
-
end
|
12
|
-
|
13
|
-
def twin_class
|
14
|
-
self[:twin].evaluate(nil) # FIXME: do we support the :twin option, and should it be wrapped?
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
# FIXME: this is not properly used when inheriting - fix that in representable.
|
19
|
-
def self.build_config
|
20
|
-
Config.new(Definition)
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.each(options={})
|
24
|
-
return representable_attrs[:definitions].values unless block_given?
|
25
|
-
|
26
|
-
definitions = representable_attrs
|
27
|
-
|
28
|
-
definitions.each do |dfn|
|
29
|
-
next if options[:exclude] and options[:exclude].include?(dfn.name)
|
30
|
-
next if options[:scalar] and dfn[:collection]
|
31
|
-
next if options[:collection] and ! dfn[:collection]
|
32
|
-
next if options[:twin] and ! dfn[:twin]
|
33
|
-
|
34
|
-
yield dfn
|
35
|
-
end
|
36
|
-
|
37
|
-
definitions
|
38
|
-
end
|
39
|
-
|
40
|
-
def self.default_inline_class
|
41
|
-
Twin
|
42
|
-
end
|
43
|
-
|
44
|
-
|
45
|
-
class Options < ::Hash
|
46
|
-
def exclude!(names)
|
47
|
-
excludes.push(*names)
|
48
|
-
self
|
49
|
-
end
|
50
|
-
|
51
|
-
def excludes
|
52
|
-
self[:exclude] ||= []
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end # Decorator.
|
56
|
-
end
|
57
|
-
end
|