disposable 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a86781957ac37581fc914a2f8dc9ca83b67d47e1
4
- data.tar.gz: 0a994524733877ec59edb02ce050272b447e9409
3
+ metadata.gz: 3028d579eaa9e41a6d3591c069809c98940bd7a1
4
+ data.tar.gz: 12371d78cdf1c2bfe046021f45ffb0a1dbd4ccff
5
5
  SHA512:
6
- metadata.gz: 94b995707bba8d65c9361ae3c0b50cfbd23d2c72f2f0212791800cfe8e771a815b7cef80c4d305e9481a3e284959131cc304b3fc2a0fc97076e7d28435de3898
7
- data.tar.gz: 6f7fcd2584e0b0d06b2d4615d9d7280d0791591837750c2d515fdb0445de3677e69d397de557d3fc05e181e8877046bb3fa8ae884e7d75c55f207af1f55c537a
6
+ metadata.gz: 2af96f209c219622ac48b55d86798cd392fd83cb73e14463319d965c20a01824e4354ff5f09e9b71bddc21caeb64e369cb265478c77572226c1245297a7f25bc
7
+ data.tar.gz: e58b5545c50a104ca16ae784cb48a2280dc60a407f35345dcccf78e867756380993826be1e6d4ce5f442475f0fd1311fddc4f2079f467cf5d1b774ce05b44c07
data/Gemfile CHANGED
@@ -3,4 +3,4 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in disposable.gemspec
4
4
  gemspec
5
5
 
6
- # gem 'representable', path: '../representable'
6
+ #gem 'representable', path: '../representable'
data/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # Disposable
2
2
 
3
3
 
4
+ why?
5
+ because i want this to fuckin work: Wallpaper.find(51).update_attributes(enabled:false)
6
+
4
7
 
5
8
  ## Twin
6
9
 
@@ -82,6 +85,12 @@ song.save # write to DB.
82
85
 
83
86
 
84
87
 
88
+ ## Composition
89
+
90
+ hiding composed datastructures
91
+ mapping methods, with optional as:
92
+
93
+
85
94
  ## To be documented properly
86
95
 
87
96
  Facade existing (model) class
data/STUFF CHANGED
@@ -1,11 +1,4 @@
1
1
  USE CASE:
2
2
 
3
3
  <% client.invoices.outstanding.each do |invoice| %>
4
- <%= link_to invoice.invoice_number, {:controller => "party", :action => "invoice_show", :id => invoice.id, :entity_instance_id => client.party, :entity_type_id => EntityType::PARTY}, :onclick => "event.cancelBubble=true;" %> <%= number_to_currency(invoice.balance_out)
5
-
6
-
7
- Invoice::Option::Rate <-- uses option everywhere
8
- make that declaratively hook-able:
9
- belongs_to Invoice::Option
10
-
11
- Invoice::Option#rate => Rate.new(self)
4
+ <%= link_to invoice.invoice_number, {:controller => "party", :action => "invoice_show", :id => invoice.id, :entity_instance_id => client.party, :entity_type_id => EntityType::PARTY}, :onclick => "event.cancelBubble=true;" %> <%= number_to_currency(invoice.balance_out)
data/database.sqlite3 CHANGED
Binary file
data/disposable.gemspec CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_dependency "uber"
22
- spec.add_dependency "representable"
22
+ spec.add_dependency "representable", "~> 1.8.1"
23
23
 
24
24
  spec.add_development_dependency "bundler", "~> 1.3"
25
25
  spec.add_development_dependency "rake"
@@ -1,7 +1,9 @@
1
1
  PATH
2
- remote: /home/nick/projects/disposable
2
+ remote: ../
3
3
  specs:
4
- disposable (0.0.1)
4
+ disposable (0.0.2)
5
+ representable (~> 1.8.1)
6
+ uber
5
7
 
6
8
  GEM
7
9
  remote: http://rubygems.org/
@@ -16,7 +18,11 @@ GEM
16
18
  activeresource (2.3.18)
17
19
  activesupport (= 2.3.18)
18
20
  activesupport (2.3.18)
21
+ mini_portile (0.5.3)
19
22
  minitest (5.0.8)
23
+ multi_json (1.9.3)
24
+ nokogiri (1.6.1)
25
+ mini_portile (~> 0.5.0)
20
26
  rack (1.1.6)
21
27
  rails (2.3.18)
22
28
  actionmailer (= 2.3.18)
@@ -26,7 +32,12 @@ GEM
26
32
  activesupport (= 2.3.18)
27
33
  rake (>= 0.8.3)
28
34
  rake (10.1.0)
35
+ representable (1.8.1)
36
+ multi_json
37
+ nokogiri
38
+ uber
29
39
  sqlite3 (1.3.8)
40
+ uber (0.0.4)
30
41
 
31
42
  PLATFORMS
32
43
  ruby
@@ -1,7 +1,9 @@
1
1
  PATH
2
- remote: /home/nick/projects/disposable
2
+ remote: ../
3
3
  specs:
4
- disposable (0.0.1)
4
+ disposable (0.0.2)
5
+ representable (~> 1.8.1)
6
+ uber
5
7
 
6
8
  GEM
7
9
  remote: http://rubygems.org/
@@ -33,7 +35,11 @@ GEM
33
35
  abstract (>= 1.0.0)
34
36
  i18n (0.5.0)
35
37
  json (1.8.0)
38
+ mini_portile (0.5.3)
36
39
  minitest (5.0.8)
40
+ multi_json (1.9.3)
41
+ nokogiri (1.6.1)
42
+ mini_portile (~> 0.5.0)
37
43
  rack (1.2.8)
38
44
  rack-mount (0.6.14)
39
45
  rack (>= 1.0.0)
@@ -48,9 +54,14 @@ GEM
48
54
  rake (10.1.0)
49
55
  rdoc (3.12.2)
50
56
  json (~> 1.4)
57
+ representable (1.8.1)
58
+ multi_json
59
+ nokogiri
60
+ uber
51
61
  sqlite3 (1.3.8)
52
62
  thor (0.14.6)
53
63
  tzinfo (0.3.38)
64
+ uber (0.0.4)
54
65
 
55
66
  PLATFORMS
56
67
  ruby
@@ -1,40 +1,55 @@
1
+ require 'forwardable'
2
+
1
3
  module Disposable
2
4
  # Composition delegates accessors to models as per configuration.
5
+ # Composition doesn't know anything but methods (readers and writers) to expose and the mappings to
6
+ # the internal models. Optionally, it knows about renamings such as mapping `#song_id` to `song.id`.
3
7
  #
4
8
  # class Album
5
9
  # include Disposable::Composition
6
-
7
- # map( {cd: [:id, :name], band: [:title]} )
10
+ #
11
+ # map( {cd: [[:id], [:name]], band: [[:id, :band_id], [:title]]} )
8
12
  # end
9
-
13
+ #
10
14
  # album = Album.new(cd: CD.find(1), band: Band.new)
11
15
  # album.id #=> 1
12
16
  # album.title = "Ten Foot Pole"
13
17
  module Composition
14
18
  def self.included(base)
19
+ base.extend(Forwardable)
15
20
  base.extend(ClassMethods)
16
21
  end
17
22
 
23
+
18
24
  module ClassMethods
19
25
  def map(options)
20
- @attr2obj = {} # {song: ["title", "track"], artist: ["name"]}
26
+ @map = {}
21
27
 
22
28
  options.each do |mdl, meths|
23
- create_accessors(mdl, meths)
24
29
  attr_reader mdl
25
30
 
26
- meths.each { |m| @attr2obj[m.to_s] = mdl }
31
+ meths.each do |mtd| # [[:title], [:id, :song_id]]
32
+ create_accessors(mdl, mtd)
33
+ add_to_map(mdl, mtd)
34
+ end
27
35
  end
28
36
  end
29
37
 
38
+ private
30
39
  def create_accessors(model, methods)
31
- accessors = methods.collect { |m| [m, "#{m}="] }.flatten
32
- delegate *accessors << {:to => :"#{model}"}
40
+ def_instance_delegator model, *methods # reader
41
+ def_instance_delegator model, *methods.map { |m| "#{m}=" } # writer
42
+ end
43
+
44
+ def add_to_map(model, methods)
45
+ name, public_name = methods
46
+ public_name ||= name
47
+
48
+ @map[public_name.to_sym] = {:method => name.to_sym, :model => model.to_sym}
33
49
  end
34
50
  end
35
51
 
36
52
 
37
- private
38
53
  def initialize(models)
39
54
  models.each do |name, obj|
40
55
  instance_variable_set(:"@#{name}", obj)
@@ -43,6 +58,12 @@ module Disposable
43
58
  @_models = models.values
44
59
  end
45
60
 
61
+ # Allows multiplexing method calls to all composed models.
62
+ def each(&block)
63
+ _models.each(&block)
64
+ end
65
+
66
+ private
46
67
  attr_reader:_models
47
68
  end
48
69
  end
@@ -2,9 +2,6 @@ class Disposable::Facade
2
2
  module ActiveRecord
3
3
  def is_a?(klass)
4
4
  # DISCUSS: should we use facade_options here for the class?
5
- #return self.class.facade_options.first == klass if self.class.facade_options.first
6
- # DISCUSS: make ::facades obligatory?
7
-
8
5
  klass == __getobj__.class or super
9
6
  end
10
7
  end
@@ -13,36 +13,14 @@ module Disposable
13
13
  Class.new(self) # By subclassing, representable_attrs.clone is called.
14
14
  end
15
15
 
16
- def self.build_config
17
- super.extend(ConfigExtensions)
18
- end
19
-
20
- def self.twin_names
21
- representable_attrs.twin_names
22
- end
23
-
24
- def twins(&block)
25
- clone_config!.
26
- find_all { |attr| attr[:form] }.
27
- each(&block)
28
- end
29
-
30
- module ConfigExtensions
31
- def twin_names
16
+ def twin_names
17
+ representable_attrs.
32
18
  find_all { |attr| attr[:twin] }.
33
- collect { |attr| attr.name }
34
- end
35
- end
36
-
37
-
38
- class Save < self
39
-
19
+ collect { |attr| attr.name.to_sym }
40
20
  end
41
21
  end
42
22
 
43
23
 
44
-
45
-
46
24
  extend Uber::InheritableAttr
47
25
  inheritable_attr :representer_class
48
26
  self.representer_class = Class.new(Decorator)
@@ -53,10 +31,13 @@ module Disposable
53
31
  self._model = name
54
32
  end
55
33
 
56
- def self.property(name, *args, &block)
57
- attr_accessor name
34
+ def self.property(name, options={}, &block)
35
+ options[:public_name] = options.delete(:as) || name
36
+ options[:pass_options] = true
58
37
 
59
- representer_class.property(name, *args, &block)
38
+ representer_class.property(name, options, &block).tap do |definition|
39
+ attr_accessor definition[:public_name]
40
+ end
60
41
  end
61
42
 
62
43
  def self.from(model) # TODO: private.
@@ -72,49 +53,68 @@ module Disposable
72
53
  new(_model.find(id))
73
54
  end
74
55
 
56
+ # hash for #update_attributes (model API): {title: "Future World", album: <Album>}
75
57
  def self.save_representer
76
58
  # TODO: do that only at compile-time!
77
- save = Class.new(representer_class) # inherit configuration
59
+ save = Class.new(write_representer) # inherit configuration
78
60
  save.representable_attrs.
79
61
  find_all { |attr| attr[:twin] }.
80
62
  each { |attr| attr.merge!(
81
- :representable => true) }
63
+ :representable => true,
64
+ :serialize => lambda { |obj, args| obj.send(:model) }) }
65
+
66
+ save.representable_attrs.each do |attr|
67
+ attr.merge!(:as => attr.name)
68
+ end
69
+
82
70
  save
83
71
  end
84
72
 
73
+ # transform incoming model into twin API hash.
85
74
  def self.new_representer
86
75
  representer = Class.new(representer_class) # inherit configuration
76
+
77
+ # wrap incoming nested model in it's Twin.
87
78
  representer.representable_attrs.
88
79
  find_all { |attr| attr[:twin] }.
89
80
  each { |attr| attr.merge!(
90
- :pass_options => true,
91
81
  :prepare => lambda { |object, args| args.binding[:twin].new(object) }) }
92
- representer
93
- end
94
82
 
83
+ # song_title => model.title
84
+ representer.representable_attrs.each do |attr|
85
+ attr.merge!(:as => attr[:public_name])
86
+ end
95
87
 
96
- def to_hash(*) # DISCUSS: do we want that here?
97
- model
88
+ representer
98
89
  end
99
90
 
100
- # it's important to stress that #save is the only entry point where we hit the database after initialize.
101
- def save # use that in Reform::AR.
102
- twin_names = self.class.representer_class.twin_names
103
-
104
- raw_attrs = self.class.representer_class.new(self).to_hash
105
- save_attrs = raw_attrs.select { |k| twin_names.include?(k) }
106
- save_attrs.values.map(&:save)
91
+ # read/write to twin using twin's API (e.g. #record= not #album=).
92
+ def self.write_representer
93
+ 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
+ )}
107
102
 
103
+ representer
104
+ end
108
105
 
109
- sync_attrs = self.class.save_representer.new(self).to_hash
110
- # this is ORM-specific:
111
- model.update_attributes(sync_attrs) # this also does `album: #<Album>`
106
+ # call save on all nested twins.
107
+ def self.pre_save_representer
108
+ representer = Class.new(write_representer)
109
+ representer.representable_attrs.
110
+ each { |attr| attr.merge!(
111
+ :representable => true,
112
+ :serialize => lambda { |model, args| model.save }
113
+ )}
112
114
 
113
- # FIXME: sync again, here, or just id?
114
- self.id = model.id
115
+ representer
115
116
  end
116
117
 
117
- # below is the code for a representable-style twin:
118
118
 
119
119
  # TODO: improve speed when setting up a twin.
120
120
  def initialize(model, options={})
@@ -125,11 +125,46 @@ module Disposable
125
125
  merge(options))
126
126
  end
127
127
 
128
+ # it's important to stress that #save is the only entry point where we hit the database after initialize.
129
+ def save # use that in Reform::AR.
130
+ pre_save = self.class.pre_save_representer.new(self)
131
+ pre_save.to_hash(:include => pre_save.twin_names) # #save on nested Twins.
132
+
133
+
134
+
135
+ # what we do right now
136
+ # call save on all nested twins - how does that work with dependencies (eg Album needs Song id)?
137
+ # extract all ORM attributes
138
+ # write to model
139
+
140
+ sync_attrs = self.class.save_representer.new(self).to_hash
141
+ # puts "sync> #{sync_attrs.inspect}"
142
+ # this is ORM-specific:
143
+ model.update_attributes(sync_attrs) # this also does `album: #<Album>`
144
+
145
+ # FIXME: sync again, here, or just id?
146
+ self.id = model.id
147
+ end
148
+
128
149
  private
129
150
  def from_hash(options={})
130
- self.class.representer_class.new(self).from_hash(options)
151
+ self.class.write_representer.new(self).from_hash(options)
131
152
  end
132
153
 
133
154
  attr_reader :model # TODO: test
155
+
156
+
157
+ # class Composition < self
158
+ # def initialize(hash)
159
+ # hash = hash.first
160
+ # composition = Class.new do
161
+ # include Disposable::Composition
162
+ # map( {:song => [:song_title], :requester => [:name]})
163
+ # self
164
+ # end.new(hash)
165
+
166
+ # super(composition)
167
+ # end
168
+ # end
134
169
  end
135
170
  end
@@ -1,3 +1,3 @@
1
1
  module Disposable
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -0,0 +1,96 @@
1
+ require 'test_helper'
2
+
3
+ class CompositionTest < MiniTest::Spec
4
+ module Model
5
+ Band = Struct.new(:id, :title,)
6
+ Album = Struct.new(:id, :name)
7
+ end
8
+
9
+ module Twin
10
+ class Album #< Disposable::Twin
11
+ include Disposable::Composition
12
+
13
+ map( {:album => [[:id], [:name]],
14
+ :band => [[:id, :band_id], [:title]]
15
+ } )
16
+ end
17
+ end
18
+
19
+ let (:band) { Model::Band.new(1, "Frenzal Rhomb") }
20
+ let (:album) { Model::Album.new(2, "Dick Sandwhich") }
21
+ subject { Twin::Album.new(:album => album, :band => band) }
22
+
23
+ describe "readers" do
24
+ it { subject.id.must_equal 2 }
25
+ it { subject.band_id.must_equal 1 }
26
+ it { subject.name.must_equal "Dick Sandwhich" }
27
+ it { subject.title.must_equal "Frenzal Rhomb" }
28
+ end
29
+
30
+
31
+ describe "writers" do
32
+ before do
33
+ subject.id = 3
34
+ subject.band_id = 4
35
+ subject.name = "Eclipse"
36
+ subject.title = "Yngwie J. Malmsteen"
37
+ end
38
+
39
+ it { subject.id.must_equal 3 }
40
+ it { album.id.must_equal 3 }
41
+ it { subject.band_id.must_equal 4 }
42
+ it { band.id.must_equal 4 }
43
+ it { subject.name.must_equal "Eclipse" }
44
+ it { subject.title.must_equal "Yngwie J. Malmsteen" }
45
+ it { album.name.must_equal "Eclipse" }
46
+ it { band.title.must_equal "Yngwie J. Malmsteen" }
47
+ end
48
+ # it { subject.save }
49
+
50
+ it "raises when non-mapped property" do
51
+ assert_raises NoMethodError do
52
+ subject.raise_an_exception
53
+ end
54
+ end
55
+
56
+
57
+ describe "readers to models" do
58
+ it { subject.album.object_id.must_equal album.object_id }
59
+ it { subject.band.object_id.must_equal band.object_id }
60
+ end
61
+
62
+
63
+ describe "#each" do
64
+ it "what" do
65
+ results = []
66
+ subject.each { |mdl| results << mdl.object_id }
67
+ results.must_equal([album.object_id, band.object_id])
68
+ end
69
+ end
70
+
71
+
72
+ describe "#_models" do
73
+ it { subject.send(:_models).must_equal([album, band]) }
74
+ it { Twin::Album.new(:album => album).send(:_models).must_equal([album]) }
75
+ end
76
+
77
+
78
+ describe "@map" do
79
+ let (:composition) {
80
+ Class.new do
81
+ include Disposable::Composition
82
+
83
+ map( {:album => [["id"], [:name]],
84
+ "band" => [[:id, "band_id"], [:title]]
85
+ } )
86
+ end
87
+ }
88
+
89
+ # yepp, a private test WITH interface violation, as this is still a semi-public concept.
90
+ it { composition.instance_variable_get(:@map).must_equal({
91
+ :id => {:method=>:id, :model=>:album},
92
+ :name => {:method=>:name, :model=>:album},
93
+ :band_id => {:method=>:id, :model=>:band},
94
+ :title => {:method=>:title, :model=>:band}}) }
95
+ end
96
+ end
@@ -85,6 +85,7 @@ class TwinActiveRecordTest < MiniTest::Spec
85
85
  must_equal({"id" => subject.id, "title" => "Broken"}) }
86
86
 
87
87
  it { subject.album.must_equal album }
88
+ it { subject.album.id.wont_equal nil } # FIXME: this only works because song is saved after album.
88
89
  end
89
90
 
90
91
 
@@ -101,4 +102,63 @@ class TwinActiveRecordTest < MiniTest::Spec
101
102
 
102
103
  it { subject.album.attributes.slice("name").must_equal("name" => "Billy Talent") }
103
104
  end
104
- end
105
+ end
106
+
107
+
108
+ class TwinActiveRecordAsTest < MiniTest::Spec
109
+ module Twin
110
+ class Album < Disposable::Twin
111
+ property :id
112
+ property :name, :as => :album_name
113
+
114
+ model ::Album
115
+ end
116
+
117
+ class Song < Disposable::Twin
118
+ property :id
119
+ property :title, :as => :song_title
120
+ property :album, :twin => Album, :as => :record
121
+
122
+ model ::Song
123
+ end
124
+ end
125
+
126
+
127
+ describe "::from" do
128
+ # (existing models)
129
+ let (:song) { ::Song.new(:title => "Broken", :album => album) }
130
+ let (:album) { ::Album.new(:name => "The Process Of Belief") }
131
+
132
+ let(:twin) { Twin::Song.from(song) }
133
+
134
+ it { twin.song_title.must_equal "Broken" }
135
+ it { twin.record.album_name.must_equal "The Process Of Belief" }
136
+ end
137
+
138
+
139
+ describe "#save" do
140
+ # existing models
141
+ let (:song) { ::Song.new(:title => "Broken", :album => album) }
142
+ let (:album) { ::Album.new(:name => "The Process Of Belief") }
143
+
144
+ let(:twin) { Twin::Song.from(song) }
145
+
146
+ before do
147
+ twin.song_title = "Emo Boy"
148
+ twin.record.album_name = "Rode Hard And Put Away Wet"
149
+
150
+ twin.save
151
+ end
152
+
153
+ let (:ar_song) { ::Song.find(twin.id) }
154
+ let (:ar_album) { ar_song.album }
155
+
156
+ it { ar_song.attributes.slice("id", "title").
157
+ must_equal({"id" => ar_song.id, "title" => "Emo Boy"}) }
158
+
159
+ it { ar_album.must_equal album }
160
+ it("xxx") { ar_album.name.must_equal "Rode Hard And Put Away Wet" }
161
+ it { ar_album.id.wont_equal nil } # FIXME: this only works because song is saved after album.
162
+ end
163
+
164
+ end
@@ -1,50 +1,37 @@
1
- require 'test_helper'
1
+ # require 'test_helper'
2
2
 
3
- class CompositionTest < MiniTest::Spec
4
- module Model
5
- Band = Struct.new(:id, :title,)
6
- Album = Struct.new(:id, :name)
7
- end
3
+ # class TwinCompositionTest < MiniTest::Spec
4
+ # class Request < Disposable::Twin::Composition
5
+ # property :title, :on => :song, :as => :song_title
6
+ # property :id, :on => :song, :as => :song_id
8
7
 
9
- module Twin
10
- class Album #< Disposable::Twin
11
- include Disposable::Composition
12
- extend Disposable::Composition::ClassMethods # FIXME.
8
+ # property :name, :on => :requester
13
9
 
14
- # property :id # DISCUSS: needed for #save.
15
- # property :name, :on => :album
16
- # property :title, :on => :band # as: :band_name
10
+ # # map ...
11
+ # end
17
12
 
18
- # model Model::Album
13
+ # module Model
14
+ # Song = Struct.new(:id, :title, :album)
15
+ # Requester = Struct.new(:id, :name)
16
+ # end
19
17
 
20
- map( {:album => [:id, :name], :band => [:title]} )
21
- end
22
- end
18
+ # let (:requester) { Model::Requester.new(1, "Greg Howe") }
19
+ # let (:song) { Model::Song.new(2, "Extraction") }
23
20
 
24
- let (:band) { Model::Band.new(1, "Frenzal Rhomb") }
25
- let (:album) { Model::Album.new(2, "Dick Sandwhich") }
26
- subject { Twin::Album.new(:album => album, :band => band) }
21
+ # let (:request) { Request.new([:song => song, :requester => requester]) }
27
22
 
28
- # it { subject.id.must_equal 2 }
29
- it { subject.name.must_equal "Dick Sandwhich" }
30
- it { subject.title.must_equal "Frenzal Rhomb" }
23
+ # it { request.song_title.must_equal "Extraction" }
24
+ # it { request.name.must_equal "Greg Howe" }
31
25
 
32
- # it { subject.save }
33
26
 
34
- it "raises when non-mapped property" do
35
- assert_raises NoMethodError do
36
- subject.raise_an_exception
37
- end
38
- end
27
+ # describe "setter" do
28
+ # before do
29
+ # request.song_title = "Tease"
30
+ # request.name = "Wooten"
31
+ # end
39
32
 
40
- describe "readers to models" do
41
- it { subject.album.object_id.must_equal album.object_id }
42
- it { subject.band.object_id.must_equal band.object_id }
43
- end
44
-
45
-
46
- describe "#_models" do
47
- it { subject.send(:_models).must_equal([album, band]) }
48
- it { Twin::Album.new(:album => album).send(:_models).must_equal([album]) }
49
- end
50
- end
33
+ # it { request.song_title.must_equal "Tease" }
34
+ # it { song.title.must_equal "Tease" }
35
+ # it { request.name.must_equal "Wooten" }
36
+ # end
37
+ # end
@@ -67,9 +67,9 @@ end
67
67
 
68
68
 
69
69
  class TwinDecoratorTest < MiniTest::Spec
70
- subject { TwinTest::Twin::Song.representer_class }
70
+ subject { TwinTest::Twin::Song.representer_class.new(nil) }
71
71
 
72
- it { subject.twin_names.must_equal ["album"] }
72
+ it { subject.twin_names.must_equal [:album] }
73
73
  end
74
74
 
75
75
  # from is as close to from_hash as possible
@@ -77,3 +77,58 @@ end
77
77
 
78
78
 
79
79
  # should #new create empty associated models?
80
+
81
+
82
+ class TwinAsTest < MiniTest::Spec
83
+ module Model
84
+ Song = Struct.new(:title, :album)
85
+ Album = Struct.new(:name)
86
+ end
87
+
88
+
89
+ module Twin
90
+ class Album < Disposable::Twin
91
+ property :name, :as => :record_name
92
+
93
+ model Model::Album
94
+ end
95
+
96
+ class Song < Disposable::Twin
97
+ property :title, :as => :name
98
+ property :album, :twin => Album, :as => :record
99
+
100
+ model Model::Song
101
+ end
102
+ end
103
+
104
+
105
+ let (:record) { Twin::Album.new(:record_name => "Veni Vidi Vicous") }
106
+ subject { Twin::Song.new(:name => "Outsmarted", :record => record) }
107
+
108
+
109
+ describe "::new" do # TODO: this creates a new model!
110
+ # the Twin exposes the as: API.
111
+ it { subject.name.must_equal "Outsmarted" }
112
+ it { subject.record.must_equal record }
113
+ end
114
+
115
+ # DISCUSS: should we test saving without AR? is that worth the hustle?
116
+ # describe "#save" do
117
+ # before { subject.send(:model).instance_eval do
118
+ # def update_attributes(*)
119
+
120
+ # end
121
+ # end
122
+ # subject.save
123
+ # }
124
+
125
+
126
+
127
+ # # before { subject.save }
128
+
129
+ # it { subject.name }
130
+ # end
131
+ end
132
+
133
+
134
+ # TODO: test coercion!
metadata CHANGED
@@ -1,111 +1,111 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: disposable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
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-04-25 00:00:00.000000000 Z
11
+ date: 2014-04-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: uber
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: representable
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: 1.8.1
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: 1.8.1
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '1.3'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.3'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: minitest
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '>='
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '>='
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: activerecord
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - '>='
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - '>='
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: sqlite3
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - '>='
101
+ - - ">="
102
102
  - !ruby/object:Gem::Version
103
103
  version: '0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - '>='
108
+ - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  description: Domain-Oriented Refactoring Framework.
@@ -115,8 +115,8 @@ executables: []
115
115
  extensions: []
116
116
  extra_rdoc_files: []
117
117
  files:
118
- - .gitignore
119
- - .travis.yml
118
+ - ".gitignore"
119
+ - ".travis.yml"
120
120
  - Gemfile
121
121
  - LICENSE.txt
122
122
  - README.md
@@ -135,6 +135,7 @@ files:
135
135
  - lib/disposable/twin.rb
136
136
  - lib/disposable/version.rb
137
137
  - test/active_record_test.rb
138
+ - test/composition_test.rb
138
139
  - test/facade_test.rb
139
140
  - test/test_helper.rb
140
141
  - test/twin/active_record_test.rb
@@ -150,24 +151,26 @@ require_paths:
150
151
  - lib
151
152
  required_ruby_version: !ruby/object:Gem::Requirement
152
153
  requirements:
153
- - - '>='
154
+ - - ">="
154
155
  - !ruby/object:Gem::Version
155
156
  version: '0'
156
157
  required_rubygems_version: !ruby/object:Gem::Requirement
157
158
  requirements:
158
- - - '>='
159
+ - - ">="
159
160
  - !ruby/object:Gem::Version
160
161
  version: '0'
161
162
  requirements: []
162
163
  rubyforge_project:
163
- rubygems_version: 2.2.2
164
+ rubygems_version: 2.2.1
164
165
  signing_key:
165
166
  specification_version: 4
166
167
  summary: Domain-Oriented Refactoring Framework.
167
168
  test_files:
168
169
  - test/active_record_test.rb
170
+ - test/composition_test.rb
169
171
  - test/facade_test.rb
170
172
  - test/test_helper.rb
171
173
  - test/twin/active_record_test.rb
172
174
  - test/twin/composition_test.rb
173
175
  - test/twin/twin_test.rb
176
+ has_rdoc: