disposable 0.0.2 → 0.0.3

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 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: