disposable 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|