disposable 0.0.3 → 0.0.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/CHANGES.md +3 -0
- data/README.md +1 -1
- data/database.sqlite3 +0 -0
- data/lib/disposable/composition.rb +11 -5
- data/lib/disposable/twin.rb +11 -15
- data/lib/disposable/version.rb +1 -1
- data/test/composition_test.rb +13 -7
- data/test/twin/active_record_test.rb +3 -3
- data/test/twin/twin_test.rb +19 -9
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9f223895880d3cf7e132a9fc7fe289d2364cda94
|
4
|
+
data.tar.gz: f6fb9b0b50ab1f76f6a76c233bc6a7b764d715c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b419406d81071ac149d0bb88a4b4165763b752be5530125ddb4a2165b05ffb704087cc5502d37bde78ef75b132bf49b101d9b7ec475ef3754904619f5039cae9
|
7
|
+
data.tar.gz: 8f18dd625473e5880a7a600698bb36eef37cf1791df67ed59e91c9f0179e168d16a32e201002afa8d3bbb85f75d426b88fb5c28f7958d19404d8a8b1878112a9
|
data/CHANGES.md
ADDED
data/README.md
CHANGED
data/database.sqlite3
CHANGED
Binary file
|
@@ -2,6 +2,7 @@ require 'forwardable'
|
|
2
2
|
|
3
3
|
module Disposable
|
4
4
|
# Composition delegates accessors to models as per configuration.
|
5
|
+
#
|
5
6
|
# Composition doesn't know anything but methods (readers and writers) to expose and the mappings to
|
6
7
|
# the internal models. Optionally, it knows about renamings such as mapping `#song_id` to `song.id`.
|
7
8
|
#
|
@@ -14,6 +15,8 @@ module Disposable
|
|
14
15
|
# album = Album.new(cd: CD.find(1), band: Band.new)
|
15
16
|
# album.id #=> 1
|
16
17
|
# album.title = "Ten Foot Pole"
|
18
|
+
#
|
19
|
+
# It allows accessing the contained models using the `#[]` reader.
|
17
20
|
module Composition
|
18
21
|
def self.included(base)
|
19
22
|
base.extend(Forwardable)
|
@@ -26,8 +29,6 @@ module Disposable
|
|
26
29
|
@map = {}
|
27
30
|
|
28
31
|
options.each do |mdl, meths|
|
29
|
-
attr_reader mdl
|
30
|
-
|
31
32
|
meths.each do |mtd| # [[:title], [:id, :song_id]]
|
32
33
|
create_accessors(mdl, mtd)
|
33
34
|
add_to_map(mdl, mtd)
|
@@ -37,8 +38,8 @@ module Disposable
|
|
37
38
|
|
38
39
|
private
|
39
40
|
def create_accessors(model, methods)
|
40
|
-
def_instance_delegator model, *methods # reader
|
41
|
-
def_instance_delegator model, *methods.map { |m| "#{m}=" } # writer
|
41
|
+
def_instance_delegator "@#{model}", *methods # reader
|
42
|
+
def_instance_delegator "@#{model}", *methods.map { |m| "#{m}=" } # writer
|
42
43
|
end
|
43
44
|
|
44
45
|
def add_to_map(model, methods)
|
@@ -58,12 +59,17 @@ module Disposable
|
|
58
59
|
@_models = models.values
|
59
60
|
end
|
60
61
|
|
62
|
+
# Allows accessing the contained models.
|
63
|
+
def [](name)
|
64
|
+
instance_variable_get(:"@#{name}")
|
65
|
+
end
|
66
|
+
|
61
67
|
# Allows multiplexing method calls to all composed models.
|
62
68
|
def each(&block)
|
63
69
|
_models.each(&block)
|
64
70
|
end
|
65
71
|
|
66
72
|
private
|
67
|
-
attr_reader:_models
|
73
|
+
attr_reader :_models
|
68
74
|
end
|
69
75
|
end
|
data/lib/disposable/twin.rb
CHANGED
@@ -32,14 +32,18 @@ module Disposable
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def self.property(name, options={}, &block)
|
35
|
-
options[:
|
35
|
+
options[:private_name] = options.delete(:as) || name
|
36
36
|
options[:pass_options] = true
|
37
37
|
|
38
38
|
representer_class.property(name, options, &block).tap do |definition|
|
39
|
-
attr_accessor
|
39
|
+
attr_accessor name
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
+
def self.collection(name, options={}, &block)
|
44
|
+
property(name, options.merge(:collection => true), &block)
|
45
|
+
end
|
46
|
+
|
43
47
|
def self.from(model) # TODO: private.
|
44
48
|
new(model)
|
45
49
|
end
|
@@ -64,7 +68,7 @@ module Disposable
|
|
64
68
|
:serialize => lambda { |obj, args| obj.send(:model) }) }
|
65
69
|
|
66
70
|
save.representable_attrs.each do |attr|
|
67
|
-
attr.merge!(:as => attr
|
71
|
+
attr.merge!(:as => attr[:private_name])
|
68
72
|
end
|
69
73
|
|
70
74
|
save
|
@@ -78,11 +82,13 @@ module Disposable
|
|
78
82
|
representer.representable_attrs.
|
79
83
|
find_all { |attr| attr[:twin] }.
|
80
84
|
each { |attr| attr.merge!(
|
81
|
-
:prepare => lambda { |object, args| args.binding[:twin].new(object) }) }
|
85
|
+
:prepare => lambda { |object, args| args.binding[:twin].call.new(object) }) }
|
82
86
|
|
83
87
|
# song_title => model.title
|
84
88
|
representer.representable_attrs.each do |attr|
|
85
|
-
attr.merge!(
|
89
|
+
attr.merge!(
|
90
|
+
:getter => lambda { |args| send("#{args.binding[:private_name]}") },
|
91
|
+
)
|
86
92
|
end
|
87
93
|
|
88
94
|
representer
|
@@ -91,16 +97,6 @@ module Disposable
|
|
91
97
|
# read/write to twin using twin's API (e.g. #record= not #album=).
|
92
98
|
def self.write_representer
|
93
99
|
representer = Class.new(representer_class) # inherit configuration
|
94
|
-
representer.representable_attrs.
|
95
|
-
each { |attr| attr.merge!(
|
96
|
-
# use the alias name (as:) when writing attributes in new.
|
97
|
-
# DISCUSS: attr.name = public_name would be simpler.
|
98
|
-
:as => attr[:public_name],
|
99
|
-
:getter => lambda { |args| send("#{args.binding[:public_name]}") },
|
100
|
-
:setter => lambda { |value, args| send("#{args.binding[:public_name]}=", value) }
|
101
|
-
)}
|
102
|
-
|
103
|
-
representer
|
104
100
|
end
|
105
101
|
|
106
102
|
# call save on all nested twins.
|
data/lib/disposable/version.rb
CHANGED
data/test/composition_test.rb
CHANGED
@@ -3,27 +3,28 @@ require 'test_helper'
|
|
3
3
|
class CompositionTest < MiniTest::Spec
|
4
4
|
module Model
|
5
5
|
Band = Struct.new(:id, :title,)
|
6
|
-
Album = Struct.new(:id, :name)
|
6
|
+
Album = Struct.new(:id, :name, :album)
|
7
7
|
end
|
8
8
|
|
9
9
|
module Twin
|
10
10
|
class Album #< Disposable::Twin
|
11
11
|
include Disposable::Composition
|
12
12
|
|
13
|
-
map( {:album => [[:id], [:name]],
|
13
|
+
map( {:album => [[:id], [:name], [:album]],
|
14
14
|
:band => [[:id, :band_id], [:title]]
|
15
15
|
} )
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
19
|
let (:band) { Model::Band.new(1, "Frenzal Rhomb") }
|
20
|
-
let (:album) { Model::Album.new(2, "Dick
|
20
|
+
let (:album) { Model::Album.new(2, "Dick Sandwich", "For the Term of Their Unnatural Lives") }
|
21
21
|
subject { Twin::Album.new(:album => album, :band => band) }
|
22
22
|
|
23
23
|
describe "readers" do
|
24
24
|
it { subject.id.must_equal 2 }
|
25
25
|
it { subject.band_id.must_equal 1 }
|
26
|
-
it { subject.name.must_equal "Dick
|
26
|
+
it { subject.name.must_equal "Dick Sandwich" }
|
27
|
+
it { subject.album.must_equal "For the Term of Their Unnatural Lives" }
|
27
28
|
it { subject.title.must_equal "Frenzal Rhomb" }
|
28
29
|
end
|
29
30
|
|
@@ -34,6 +35,7 @@ class CompositionTest < MiniTest::Spec
|
|
34
35
|
subject.band_id = 4
|
35
36
|
subject.name = "Eclipse"
|
36
37
|
subject.title = "Yngwie J. Malmsteen"
|
38
|
+
subject.album = "Best Of"
|
37
39
|
end
|
38
40
|
|
39
41
|
it { subject.id.must_equal 3 }
|
@@ -44,6 +46,8 @@ class CompositionTest < MiniTest::Spec
|
|
44
46
|
it { subject.title.must_equal "Yngwie J. Malmsteen" }
|
45
47
|
it { album.name.must_equal "Eclipse" }
|
46
48
|
it { band.title.must_equal "Yngwie J. Malmsteen" }
|
49
|
+
it { subject.album.must_equal "Best Of" }
|
50
|
+
it { album.album.must_equal "Best Of" }
|
47
51
|
end
|
48
52
|
# it { subject.save }
|
49
53
|
|
@@ -54,9 +58,11 @@ class CompositionTest < MiniTest::Spec
|
|
54
58
|
end
|
55
59
|
|
56
60
|
|
57
|
-
describe "
|
58
|
-
it { subject
|
59
|
-
it { subject
|
61
|
+
describe "#[]" do
|
62
|
+
it { subject[:album].object_id.must_equal album.object_id }
|
63
|
+
it { subject[:band].object_id.must_equal band.object_id }
|
64
|
+
|
65
|
+
it { assert_raises( NoMethodError) { subject.song } } # no reader to contained model.
|
60
66
|
end
|
61
67
|
|
62
68
|
|
@@ -109,15 +109,15 @@ class TwinActiveRecordAsTest < MiniTest::Spec
|
|
109
109
|
module Twin
|
110
110
|
class Album < Disposable::Twin
|
111
111
|
property :id
|
112
|
-
property :
|
112
|
+
property :album_name, :as => :name
|
113
113
|
|
114
114
|
model ::Album
|
115
115
|
end
|
116
116
|
|
117
117
|
class Song < Disposable::Twin
|
118
118
|
property :id
|
119
|
-
property :
|
120
|
-
property :
|
119
|
+
property :song_title, :as => :title
|
120
|
+
property :record, :twin => Album, :as => :album
|
121
121
|
|
122
122
|
model ::Song
|
123
123
|
end
|
data/test/twin/twin_test.rb
CHANGED
@@ -4,14 +4,18 @@ require 'test_helper'
|
|
4
4
|
class TwinTest < MiniTest::Spec
|
5
5
|
module Model
|
6
6
|
Song = Struct.new(:id, :title, :album)
|
7
|
-
Album = Struct.new(:id, :name)
|
7
|
+
Album = Struct.new(:id, :name, :songs)
|
8
8
|
end
|
9
9
|
|
10
10
|
|
11
11
|
module Twin
|
12
|
+
class Song < Disposable::Twin
|
13
|
+
end
|
14
|
+
|
12
15
|
class Album < Disposable::Twin
|
13
16
|
property :id # DISCUSS: needed for #save.
|
14
17
|
property :name
|
18
|
+
collection :songs, :twin => Song
|
15
19
|
|
16
20
|
model Model::Album
|
17
21
|
end
|
@@ -27,20 +31,25 @@ class TwinTest < MiniTest::Spec
|
|
27
31
|
|
28
32
|
|
29
33
|
describe "::new" do # TODO: this creates a new model!
|
30
|
-
|
34
|
+
let(:album) { Twin::Album.new }
|
35
|
+
let (:song) { Twin::Song.new }
|
31
36
|
|
32
|
-
it {
|
33
|
-
it {
|
37
|
+
it { album.name.must_equal nil }
|
38
|
+
it { album.songs.must_equal nil }
|
39
|
+
it { song.title.must_equal nil }
|
40
|
+
it { song.album.must_equal nil }
|
34
41
|
end
|
35
42
|
|
36
43
|
|
37
44
|
describe "::new with arguments" do
|
38
|
-
let (:
|
45
|
+
let (:talking) { Twin::Song.new("title" => "Talking") }
|
46
|
+
let (:album) { Twin::Album.new(:name => "30 Years", :songs => [talking]) }
|
39
47
|
subject { Twin::Song.new("title" => "Broken", "album" => album) }
|
40
48
|
|
41
49
|
it { subject.title.must_equal "Broken" }
|
42
50
|
it { subject.album.must_equal album }
|
43
51
|
it { subject.album.name.must_equal "30 Years" }
|
52
|
+
it { album.songs.must_equal [talking] }
|
44
53
|
end
|
45
54
|
|
46
55
|
|
@@ -55,13 +64,14 @@ class TwinTest < MiniTest::Spec
|
|
55
64
|
# DISCUSS: make ::from private.
|
56
65
|
describe "::from" do
|
57
66
|
let (:song) { Model::Song.new(1, "Broken", album) }
|
58
|
-
let (:album) { Model::Album.new(2, "The Process Of Belief") }
|
67
|
+
let (:album) { Model::Album.new(2, "The Process Of Belief", [Model::Song.new(3, "Dr. Stein")]) }
|
59
68
|
|
60
69
|
subject {Twin::Song.from(song) }
|
61
70
|
|
62
71
|
it { subject.title.must_equal "Broken" }
|
63
72
|
it { subject.album.must_be_kind_of Twin::Album }
|
64
73
|
it { subject.album.name.must_equal album.name }
|
74
|
+
it { subject.album.songs.first.title.must_equal "Dr. Stein" } # TODO: more tests on collections and object identity (if we need that).
|
65
75
|
end
|
66
76
|
end
|
67
77
|
|
@@ -88,14 +98,14 @@ class TwinAsTest < MiniTest::Spec
|
|
88
98
|
|
89
99
|
module Twin
|
90
100
|
class Album < Disposable::Twin
|
91
|
-
property :
|
101
|
+
property :record_name, :as => :name
|
92
102
|
|
93
103
|
model Model::Album
|
94
104
|
end
|
95
105
|
|
96
106
|
class Song < Disposable::Twin
|
97
|
-
property :
|
98
|
-
property :
|
107
|
+
property :name, :as => :title
|
108
|
+
property :record, :twin => Album, :as => :album
|
99
109
|
|
100
110
|
model Model::Song
|
101
111
|
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.0.
|
4
|
+
version: 0.0.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: 2014-
|
11
|
+
date: 2014-05-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: uber
|
@@ -117,6 +117,7 @@ extra_rdoc_files: []
|
|
117
117
|
files:
|
118
118
|
- ".gitignore"
|
119
119
|
- ".travis.yml"
|
120
|
+
- CHANGES.md
|
120
121
|
- Gemfile
|
121
122
|
- LICENSE.txt
|
122
123
|
- README.md
|