pod4 0.10.6 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +5 -5
  2. data/.bugs/bugs +2 -1
  3. data/.bugs/details/b5368c7ef19065fc597b5692314da71772660963.txt +53 -0
  4. data/.hgtags +1 -0
  5. data/Gemfile +5 -5
  6. data/README.md +157 -46
  7. data/lib/pod4/basic_model.rb +9 -22
  8. data/lib/pod4/connection.rb +67 -0
  9. data/lib/pod4/connection_pool.rb +154 -0
  10. data/lib/pod4/errors.rb +20 -0
  11. data/lib/pod4/interface.rb +34 -12
  12. data/lib/pod4/model.rb +32 -27
  13. data/lib/pod4/nebulous_interface.rb +25 -30
  14. data/lib/pod4/null_interface.rb +22 -16
  15. data/lib/pod4/pg_interface.rb +84 -104
  16. data/lib/pod4/sequel_interface.rb +138 -82
  17. data/lib/pod4/tds_interface.rb +83 -70
  18. data/lib/pod4/tweaking.rb +105 -0
  19. data/lib/pod4/version.rb +1 -1
  20. data/md/breaking_changes.md +80 -0
  21. data/spec/common/basic_model_spec.rb +67 -70
  22. data/spec/common/connection_pool_parallelism_spec.rb +154 -0
  23. data/spec/common/connection_pool_spec.rb +246 -0
  24. data/spec/common/connection_spec.rb +129 -0
  25. data/spec/common/model_ai_missing_id_spec.rb +256 -0
  26. data/spec/common/model_plus_encrypting_spec.rb +16 -4
  27. data/spec/common/model_plus_tweaking_spec.rb +128 -0
  28. data/spec/common/model_plus_typecasting_spec.rb +10 -4
  29. data/spec/common/model_spec.rb +283 -363
  30. data/spec/common/nebulous_interface_spec.rb +159 -108
  31. data/spec/common/null_interface_spec.rb +88 -65
  32. data/spec/common/sequel_interface_pg_spec.rb +217 -161
  33. data/spec/common/shared_examples_for_interface.rb +50 -50
  34. data/spec/jruby/sequel_encrypting_jdbc_pg_spec.rb +1 -1
  35. data/spec/jruby/sequel_interface_jdbc_ms_spec.rb +3 -3
  36. data/spec/jruby/sequel_interface_jdbc_pg_spec.rb +3 -23
  37. data/spec/mri/pg_encrypting_spec.rb +1 -1
  38. data/spec/mri/pg_interface_spec.rb +311 -223
  39. data/spec/mri/sequel_encrypting_spec.rb +1 -1
  40. data/spec/mri/sequel_interface_spec.rb +177 -180
  41. data/spec/mri/tds_encrypting_spec.rb +1 -1
  42. data/spec/mri/tds_interface_spec.rb +296 -212
  43. data/tags +340 -174
  44. metadata +19 -11
  45. data/md/fixme.md +0 -3
  46. data/md/roadmap.md +0 -125
  47. data/md/typecasting.md +0 -80
  48. data/spec/common/model_new_validate_spec.rb +0 -204
@@ -33,7 +33,10 @@ describe "(Model with Encryption)" do
33
33
  encrypted_columns :name, :ailment, :prescription
34
34
  set_key "dflkasdgklajndgn"
35
35
  set_iv_column :nonce
36
- set_interface NullInterface.new(:id, :nhs_no, :name, :ailment, :prescription, :nonce, [])
36
+
37
+ ifce = NullInterface.new(:id, :nhs_no, :name, :ailment, :prescription, :nonce, [])
38
+ ifce.id_ai = false
39
+ set_interface ifce
37
40
  end
38
41
  end
39
42
 
@@ -44,7 +47,10 @@ describe "(Model with Encryption)" do
44
47
  encrypted_columns :name, :ailment, :prescription
45
48
  set_key "d"
46
49
  set_iv_column :nonce
47
- set_interface NullInterface.new(:id, :nhs_no, :name, :ailment, :prescription, :nonce, [])
50
+
51
+ ifce = NullInterface.new(:id, :nhs_no, :name, :ailment, :prescription, :nonce, [])
52
+ ifce.id_ai = false
53
+ set_interface ifce
48
54
  end
49
55
  end
50
56
 
@@ -55,7 +61,10 @@ describe "(Model with Encryption)" do
55
61
  encrypted_columns :name, :ailment, :prescription
56
62
  set_key nil
57
63
  set_iv_column :nonce
58
- set_interface NullInterface.new(:id, :nhs_no, :name, :ailment, :prescription, :nonce, [])
64
+
65
+ ifce = NullInterface.new(:id, :nhs_no, :name, :ailment, :prescription, :nonce, [])
66
+ ifce.id_ai = false
67
+ set_interface ifce
59
68
  end
60
69
  end
61
70
 
@@ -65,7 +74,10 @@ describe "(Model with Encryption)" do
65
74
  attr_columns :id, :date, :heading, :text
66
75
  encrypted_columns :heading, :text
67
76
  set_key "dflkasdgklajndgn"
68
- set_interface NullInterface.new(:id, :date, :heading, :text, [])
77
+
78
+ ifce = NullInterface.new(:id, :date, :heading, :text, [])
79
+ ifce.id_ai = false
80
+ set_interface ifce
69
81
  end
70
82
  end
71
83
 
@@ -0,0 +1,128 @@
1
+ require "octothorpe"
2
+ require "bigdecimal"
3
+
4
+ require "pod4"
5
+ require "pod4/tweaking"
6
+ require "pod4/interface"
7
+
8
+
9
+ describe "(Model plus Tweaking)" do
10
+
11
+ # ##
12
+ # # I can't use NullInterface this time because I need to define a custom method on the interface.
13
+ # # But I'm _only_ calling that custom method, and there is nothing to say that the custom method
14
+ # # actually has to talk to a database...
15
+ # #
16
+ # let(:customer_interface_class) do
17
+ # Class.new Pod4::Interface do
18
+ #
19
+ # def my_list(*args)
20
+ # end
21
+ # end
22
+ # end
23
+
24
+ let(:customer_model_class) do
25
+ Class.new Pod4::Model do
26
+ include Pod4::Tweaking
27
+
28
+ class MyInterface < Pod4::Interface
29
+ attr_writer :response
30
+
31
+ # stuff that lets us fake being an interface
32
+ def initialize; end
33
+ def id_fld; :id; end
34
+
35
+ def test; end # something we can use to test attr_columns method
36
+ def thing; end # there's already a method called this on the model
37
+
38
+ # main test method; responds with whatever we want it to
39
+ def my_list(*args)
40
+ @response
41
+ end
42
+ end
43
+
44
+ attr_columns :id, :code, :band
45
+ set_interface MyInterface.new
46
+ set_custom_list :my_list
47
+
48
+ def thing; end
49
+
50
+ end
51
+ end
52
+
53
+
54
+ describe "Model.set_custom_list" do
55
+
56
+ it "requires the name of a method" do
57
+ expect{ customer_model_class.set_custom_list() }.to raise_error ArgumentError
58
+ expect{ customer_model_class.set_custom_list(:test) }.not_to raise_error
59
+ end
60
+
61
+ it "raises an ArgumentError if the method does not exist on the interface" do
62
+ expect{ customer_model_class.set_custom_list(:nope) }.to raise_error ArgumentError
63
+ end
64
+
65
+ it "raises an ArgumentError if the method already exists on the model" do
66
+ expect{ customer_model_class.set_custom_list(:thing) }.to raise_error ArgumentError
67
+ end
68
+
69
+ it "creates the corresponding method on the model class" do
70
+ expect( customer_model_class ).to respond_to :my_list
71
+ end
72
+
73
+ end # of Model.set_custom_list
74
+
75
+
76
+ describe "(custom method on model)" do
77
+
78
+ it "passes the arguments given it through to the interface method of the same name" do
79
+ expect( customer_model_class.interface )
80
+ .to receive(:my_list).with(:foo, 1, "bar")
81
+ .and_call_original
82
+
83
+ customer_model_class.interface.response = []
84
+ customer_model_class.my_list(:foo, 1, "bar")
85
+ end
86
+
87
+ it "raises Pod4Error if the return value is not an Array" do
88
+ customer_model_class.interface.response = :nope
89
+ expect{ customer_model_class.my_list(:foo) }.to raise_error(Pod4Error, /array/i)
90
+ end
91
+
92
+ it "raises Pod4Error if the return value is not an Array of Octothorpe/Hash" do
93
+ customer_model_class.interface.response = [:nope]
94
+ expect{ customer_model_class.my_list }.to raise_error(Pod4Error, /hash|record/i)
95
+ end
96
+
97
+ it "raises Pod4Error if any of the returned Octothorpe/Hashes are missing the ID field" do
98
+ customer_model_class.interface.response = [{id: 1, code: "one"}, {code: 2}]
99
+ expect{ customer_model_class.my_list }.to raise_error(Pod4Error, /ID/i)
100
+ end
101
+
102
+ it "returns an empty array if the interface method returns an empty array" do
103
+ customer_model_class.interface.response = []
104
+ expect{ customer_model_class.my_list }.not_to raise_error
105
+ expect( customer_model_class.my_list ).to eq([])
106
+ end
107
+
108
+ it "returns an array of model instances based on the results of the interface method" do
109
+ rows = [ {id: 1, code: "one"},
110
+ {id: 3, code: "three"},
111
+ {id: 5, code: "five", band: 12} ]
112
+
113
+ customer_model_class.interface.response = rows
114
+ list = customer_model_class.my_list
115
+
116
+ expect( list ).to be_an Array
117
+ expect( list ).to all( be_a customer_model_class )
118
+ expect( list.map(&:id) ).to match_array( rows.map{|x| x[:id]} )
119
+ expect( list.map(&:code) ).to match_array( rows.map{|x| x[:code]} )
120
+ expect( list.find{|x| x.id == 5}.band ).to eq 12
121
+ end
122
+
123
+
124
+ end # of (custom method on model)
125
+
126
+
127
+ end
128
+
@@ -6,14 +6,16 @@ require "pod4/typecasting"
6
6
  require "pod4/null_interface"
7
7
 
8
8
 
9
- describe "ProductModel" do
9
+ describe "(Model plus typecasting)" do
10
10
 
11
11
  let(:product_model_class) do
12
12
  Class.new Pod4::Model do
13
13
  include Pod4::TypeCasting
14
14
  force_encoding Encoding::ISO_8859_1 # I assume we are running as UTF8 here
15
15
  attr_columns :id, :code, :product, :price
16
- set_interface NullInterface.new(:id, :code, :product, :price, [])
16
+ ifce = NullInterface.new(:id, :code, :product, :price, [])
17
+ ifce.id_ai = false
18
+ set_interface ifce
17
19
  end
18
20
  end
19
21
 
@@ -28,8 +30,12 @@ describe "ProductModel" do
28
30
  typecast :flag, as: :boolean
29
31
  typecast :foo, use: :mycast, bar: 42
30
32
  typecast :bar, as: Float
31
- set_interface NullInterface.new( :id, :code, :band, :sales, :created, :yrstart,
32
- :flag, :foo, :bar, [] )
33
+
34
+ ifce = NullInterface.new( :id, :code, :band, :sales, :created, :yrstart,
35
+ :flag, :foo, :bar, [] )
36
+
37
+ ifce.id_ai = false
38
+ set_interface ifce
33
39
 
34
40
  def mycast(value, opts); "blarg"; end
35
41
  end
@@ -1,39 +1,35 @@
1
- require 'octothorpe'
1
+ require "octothorpe"
2
2
 
3
- require 'pod4/model'
4
- require 'pod4/null_interface'
3
+ require "pod4/model"
4
+ require "pod4/null_interface"
5
5
 
6
6
 
7
- describe 'CustomerModel' do
7
+ describe "Model" do
8
8
 
9
9
  ##
10
10
  # We define a model class to test, since in normal operation we would never use Model directly,
11
11
  # and since it needs an inner Interface.
12
12
  #
13
- # We define an inner class based on the genuinely existing, non-mock NullInterface class; and
14
- # then define expectations on it. When we do this, Rspec fails to pass the call on to the object,
15
- # unless we specifically say `.and_call_original` instead of `.and_return`.
16
- #
17
- # This is actually quite nice, but more than a little confusing when you see it for the first
18
- # time. Its use isn't spelled out in the RSpec docs AFAICS.
19
- #
20
- # (Also, we define the class inside an Rspec 'let' so that its scope is limited to this test.)
21
- #
22
13
  let(:customer_model_class) do
23
14
  Class.new Pod4::Model do
24
15
  attr_columns :id, :name, :groups
25
16
  attr_columns :price # specifically testing multiple calls to attr_columns
26
- set_interface NullInterface.new(:id, :name, :price, :groups, [])
17
+
18
+ set_interface NullInterface.new(:id, :name, :price, :groups,
19
+ [ {id: 1, name: "Gomez", price: 1.23, groups: "trains" },
20
+ {id: 2, name: "Morticia", price: 2.34, groups: "spanish" },
21
+ {id: 3, name: "Wednesday", price: 3.45, groups: "school" },
22
+ {id: 4, name: "Pugsley", price: 4.56, groups: "trains,school"} ] )
27
23
 
28
24
  def map_to_model(ot)
29
25
  super
30
- @groups = @groups ? @groups.split(',') : []
26
+ @groups = @groups ? @groups.split(",") : []
31
27
  self
32
28
  end
33
29
 
34
30
  def map_to_interface
35
31
  x = super
36
- g = (x.>>.groups || []).join(',')
32
+ g = (x.>>.groups || []).join(",")
37
33
  x.merge(groups: g)
38
34
  end
39
35
 
@@ -41,7 +37,7 @@ describe 'CustomerModel' do
41
37
  add_alert(*args) #private method
42
38
  end
43
39
 
44
- def validate
40
+ def validate(vmode)
45
41
  add_alert(:error, "falling over now") if name == "fall over"
46
42
  end
47
43
 
@@ -49,11 +45,36 @@ describe 'CustomerModel' do
49
45
  end
50
46
  end
51
47
 
48
+ # Here's a second model for a non-autoincrementing table
49
+ let(:product_model_class) do
50
+ Class.new Pod4::Model do
51
+ i = NullInterface.new(:code, :level, [{code: "foo", level: 1},
52
+ {code: "bar", level: 2}] )
53
+
54
+ i.id_ai = false
55
+
56
+ attr_columns :code, :level
57
+ set_interface i
58
+ end
59
+ end
60
+
61
+
62
+ def without_groups(ot)
63
+ ot.to_h.reject {|k,_| k == :groups}
64
+ end
65
+
66
+ def arr_without_groups(arr)
67
+ arr
68
+ .map {|m| without_groups(m.to_ot) }
69
+ .flatten
70
+
71
+ end
72
+
52
73
  let(:records) do
53
- [ {id: 10, name: 'Gomez', price: 1.23, groups: 'trains' },
54
- {id: 20, name: 'Morticia', price: 2.34, groups: 'spanish' },
55
- {id: 30, name: 'Wednesday', price: 3.45, groups: 'school' },
56
- {id: 40, name: 'Pugsley', price: 4.56, groups: 'trains,school'} ]
74
+ [ {id: 1, name: "Gomez", price: 1.23, groups: "trains" },
75
+ {id: 2, name: "Morticia", price: 2.34, groups: "spanish" },
76
+ {id: 3, name: "Wednesday", price: 3.45, groups: "school" },
77
+ {id: 4, name: "Pugsley", price: 4.56, groups: "trains,school"} ]
57
78
 
58
79
  end
59
80
 
@@ -64,50 +85,34 @@ describe 'CustomerModel' do
64
85
  let(:records_as_ot) { records.map{|r| Octothorpe.new(r) } }
65
86
  let(:recordsx_as_ot) { recordsx.map{|r| Octothorpe.new(r) } }
66
87
 
67
- def without_groups(ot)
68
- ot.to_h.reject {|k,_| k == :groups}
69
- end
70
-
71
88
  # model is just a plain newly created object that you can call read on.
72
89
  # model2 and model3 are in an identical state - they have been filled with a
73
- # read(). We have two so that we can RSpec 'allow' on one and not the other.
90
+ # read(). We have two so that we can RSpec "allow" on one and not the other.
74
91
 
75
- let(:model) { customer_model_class.new(20) }
92
+ let(:model) { customer_model_class.new(2) }
76
93
 
77
94
  let(:model2) do
78
- m = customer_model_class.new(30)
95
+ m = customer_model_class.new(3)
79
96
 
80
- allow( m.interface ).to receive(:read).and_return( Octothorpe.new(records[2]) )
97
+ #allow( m.interface ).to receive(:read).and_return( Octothorpe.new(records[2]) )
81
98
  m.read.or_die
82
99
  end
83
100
 
84
101
  let(:model3) do
85
- m = customer_model_class.new(40)
102
+ m = customer_model_class.new(4)
86
103
 
87
- allow( m.interface ).to receive(:read).and_return( Octothorpe.new(records[3]) )
104
+ #allow( m.interface ).to receive(:read).and_return( Octothorpe.new(records[3]) )
88
105
  m.read.or_die
89
106
  end
90
107
 
91
- # Model4 is for a non-integer id
92
- let(:thing) { Octothorpe.new(id: 'eek', name: 'thing', price: 9.99, groups: 'scuttering') }
93
108
 
94
- let(:model4) do
95
- m = customer_model_class.new('eek')
109
+ describe "Model.attr_columns" do
96
110
 
97
- allow( m.interface ).to receive(:read).and_return(thing)
98
- m.read.or_die
99
- end
100
-
101
- ##
102
-
103
-
104
- describe 'Model.attr_columns' do
105
-
106
- it 'requires a list of columns' do
111
+ it "requires a list of columns" do
107
112
  expect( customer_model_class ).to respond_to(:attr_columns).with(1).argument
108
113
  end
109
114
 
110
- it 'exposes the columns just like attr_accessor' do
115
+ it "exposes the columns just like attr_accessor" do
111
116
  expect( customer_model_class.new ).to respond_to(:id)
112
117
  expect( customer_model_class.new ).to respond_to(:name)
113
118
  expect( customer_model_class.new ).to respond_to(:price)
@@ -120,198 +125,168 @@ describe 'CustomerModel' do
120
125
 
121
126
  # it adds the columns to Model.columns -- covered by the columns test
122
127
  end
123
- ##
124
128
 
125
129
 
126
- describe 'Model.columns' do
127
- it 'lists the columns' do
130
+ describe "Model.columns" do
131
+
132
+ it "lists the columns" do
128
133
  expect( customer_model_class.columns ).to match_array( [:id,:name,:price,:groups] )
129
134
  end
135
+
130
136
  end
131
- ##
132
137
 
133
138
 
134
- describe 'Model.set_interface' do
135
- it 'requires an Interface object' do
139
+ describe "Model.set_interface" do
140
+
141
+ it "requires an Interface object" do
136
142
  expect( customer_model_class ).to respond_to(:set_interface).with(1).argument
137
143
  end
138
144
 
139
- # it 'sets interface' - covered by the interface test
145
+ # it "sets interface" - covered by the interface test
140
146
  end
141
- ##
142
147
 
143
148
 
144
- describe 'Model.interface' do
145
- it 'is the interface object' do
149
+ describe "Model.interface" do
150
+
151
+ it "is the interface object" do
146
152
  expect( customer_model_class.interface ).to be_a_kind_of NullInterface
147
153
  expect( customer_model_class.interface.id_fld ).to eq :id
148
154
  end
149
- end
150
- ##
151
155
 
156
+ end
152
157
 
153
- describe 'Model.list' do
154
158
 
159
+ describe "Model.list" do
155
160
  let(:list1) { customer_model_class.list }
156
161
 
157
- def arr_without_groups(arr)
158
- arr
159
- .map {|m| without_groups(m.to_ot) }
160
- .flatten
161
-
162
- end
163
-
164
- it 'allows an optional selection parameter' do
162
+ it "allows an optional selection parameter" do
165
163
  expect{ customer_model_class.list }.not_to raise_exception
166
- expect{ customer_model_class.list(name: 'Betty') }.not_to raise_exception
164
+ expect{ customer_model_class.list(name: "Betty") }.not_to raise_exception
167
165
  end
168
166
 
169
- it 'returns an array of customer_model_class records' do
170
- expect( customer_model_class.interface ).
171
- to receive(:list).with(nil).
172
- and_return( records_as_ot )
173
-
167
+ it "returns an array of customer_model_class records" do
174
168
  expect( list1 ).to be_a_kind_of Array
175
169
  expect( list1 ).to all(be_a_kind_of customer_model_class)
176
170
  end
177
171
 
178
- it 'returns the data from the interface' do
179
- expect( customer_model_class.interface ).
180
- to receive(:list).with(nil).
181
- and_return(records_as_ot)
182
-
172
+ it "returns the data from the interface" do
183
173
  expect( list1.size ).to eq records.size
184
174
  expect( arr_without_groups(list1) ).to include( *recordsx )
185
175
  end
186
176
 
187
- it 'honours passed selection criteria' do
188
- hash = {price: 2.22}
189
-
190
- expect( customer_model_class.interface ).
191
- to receive(:list).with(hash).
192
- and_return( [Octothorpe.new(records[1])] )
193
-
194
- list2 = customer_model_class.list(hash)
195
- expect( list2.size ).to eq 1
196
- expect( arr_without_groups(list2).first ).to eq( recordsx[1] )
177
+ it "honours passed selection criteria" do
178
+ list = customer_model_class.list(price: 2.34)
179
+ expect( list.size ).to eq 1
180
+ expect( arr_without_groups(list).first ).to eq( recordsx[1] )
197
181
  end
198
182
 
199
- it 'returns an empty array if nothing matches' do
200
- hash = {price: 1.23}
201
-
202
- expect( customer_model_class.interface ).
203
- to receive(:list).with(hash).
204
- and_return([])
205
-
206
- expect( customer_model_class.list(hash) ).to eq []
183
+ it "returns an empty array if nothing matches" do
184
+ expect( customer_model_class.list(price: 3.21) ).to eq []
207
185
  end
208
186
 
209
- it 'returns an empty array if there are no records' do
187
+ it "returns an empty array if there are no records" do
188
+ customer_model_class.list.each{|r| r.read; r.delete}
210
189
  expect( customer_model_class.list ).to eq []
211
190
  end
212
191
 
213
- it 'calls map_to_model to set the record data' do
214
- allow( customer_model_class.interface ).
215
- to receive(:list).
216
- and_return(records_as_ot)
217
-
218
- expect( customer_model_class.list.last.groups ).to eq(['trains', 'school'])
192
+ it "calls map_to_model to set the record data" do
193
+ # groups is an array because we coded it to represent that way in the model above.
194
+ expect( customer_model_class.list.last.groups ).to eq(["trains", "school"])
219
195
  end
220
196
 
221
- end
222
- ##
197
+ end # of Model.list
223
198
 
224
199
 
225
- describe '#new' do
200
+ describe "#new" do
226
201
 
227
- it 'takes an optional ID' do
202
+ it "takes an optional ID" do
228
203
  expect{ customer_model_class.new }.not_to raise_exception
229
204
  expect{ customer_model_class.new(1) }.not_to raise_exception
230
205
  end
231
206
 
232
- it 'sets the ID attribute' do
207
+ it "sets the ID attribute" do
233
208
  expect( customer_model_class.new(23).model_id ).to eq 23
234
209
  end
235
210
 
236
- it 'sets the status to empty' do
237
- expect( customer_model_class.new.model_status ).to eq :empty
211
+ it "sets the status to unknown" do
212
+ expect( customer_model_class.new.model_status ).to eq :unknown
238
213
  end
239
214
 
240
- it 'initializes the alerts attribute' do
215
+ it "initializes the alerts attribute" do
241
216
  expect( customer_model_class.new.alerts ).to eq([])
242
217
  end
243
218
 
244
- it 'doesn''t freak out if the ID is not an integer' do
245
- expect{ customer_model_class.new("france") }.not_to raise_exception
246
- expect( customer_model_class.new("france").model_id ).to eq "france"
219
+ it "doesn't freak out if the non-autoincrementing ID is not an integer" do
220
+ expect{ product_model_class.new("france") }.not_to raise_exception
221
+ expect( product_model_class.new("france").model_id ).to eq "france"
247
222
  end
248
223
 
249
- end
250
- ##
224
+ end # of #new
251
225
 
252
226
 
253
- describe '#interface' do
254
- it 'returns the interface set in the class definition, again' do
227
+ describe "#interface" do
228
+
229
+ it "returns the interface set in the class definition, again" do
255
230
  expect( customer_model_class.new.interface ).to be_a_kind_of NullInterface
256
231
  expect( customer_model_class.new.interface.id_fld ).to eq :id
257
232
  end
258
- end
259
- ##
233
+
234
+ end # of #interface
260
235
 
261
236
 
262
- describe '#columns' do
263
- it 'returns the attr_columns list from the class definition' do
237
+ describe "#columns" do
264
238
 
239
+ it "returns the attr_columns list from the class definition" do
265
240
  expect( customer_model_class.new.columns ).
266
241
  to match_array( [:id,:name,:price,:groups] )
267
242
 
268
243
  end
269
- end
270
- ##
271
244
 
245
+ end # of #columns
272
246
 
273
- describe '#alerts' do
274
- it 'returns the list of alerts against the model' do
247
+
248
+ describe "#alerts" do
249
+
250
+ it "returns the list of alerts against the model" do
275
251
  cm = customer_model_class.new
276
- cm.fake_an_alert(:warning, :foo, 'one')
277
- cm.fake_an_alert(:error, :bar, 'two')
252
+ cm.fake_an_alert(:warning, :foo, "one")
253
+ cm.fake_an_alert(:error, :bar, "two")
278
254
 
279
255
  expect( cm.alerts.size ).to eq 2
280
256
  expect( cm.alerts.map{|a| a.message} ).to match_array(%w|one two|)
281
257
  end
282
- end
283
- ##
284
258
 
259
+ end # of #alerts
285
260
 
286
- describe '#add_alert' do
287
- # add_alert is a protected method, which is only supposed to be called
288
- # within the validate method of a subclass of Method. So we test it by
289
- # calling our alert faking method
290
261
 
291
- it 'requires type, message or type, field, message' do
262
+ describe "#add_alert" do
263
+ # add_alert is a private method, which is only supposed to be called within a subclass of
264
+ # Model. So we test it by calling our alert faking method
265
+
266
+ it "requires type, message or type, field, message" do
292
267
  expect{ model.fake_an_alert }.to raise_exception ArgumentError
293
268
  expect{ model.fake_an_alert(nil) }.to raise_exception ArgumentError
294
- expect{ model.fake_an_alert('foo') }.to raise_exception ArgumentError
269
+ expect{ model.fake_an_alert("foo") }.to raise_exception ArgumentError
295
270
 
296
- expect{ model.fake_an_alert(:error, 'foo') }.not_to raise_exception
297
- expect{ model.fake_an_alert(:warning, :name, 'bar') }.
271
+ expect{ model.fake_an_alert(:error, "foo") }.not_to raise_exception
272
+ expect{ model.fake_an_alert(:warning, :name, "bar") }.
298
273
  not_to raise_exception
299
274
 
300
275
  end
301
276
 
302
- it 'only allows valid types' do
277
+ it "only allows valid types" do
303
278
  [:brian, :werning, nil, :alert, :danger].each do |l|
304
- expect{ model.fake_an_alert(l, 'foo') }.to raise_exception ArgumentError
279
+ expect{ model.fake_an_alert(l, "foo") }.to raise_exception ArgumentError
305
280
  end
306
281
 
307
282
  [:warning, :error, :success, :info].each do |l|
308
- expect{ model.fake_an_alert(l, 'foo') }.not_to raise_exception
283
+ expect{ model.fake_an_alert(l, "foo") }.not_to raise_exception
309
284
  end
310
285
 
311
286
  end
312
287
 
313
- it 'creates an Alert and adds it to @alerts' do
314
- lurch = 'Dnhhhhhh'
288
+ it "creates an Alert and adds it to @alerts" do
289
+ lurch = "Dnhhhhhh"
315
290
  model.fake_an_alert(:error, :price, lurch)
316
291
 
317
292
  expect( model.alerts.size ).to eq 1
@@ -319,39 +294,37 @@ describe 'CustomerModel' do
319
294
  expect( model.alerts.first.message ).to eq lurch
320
295
  end
321
296
 
322
- it 'sets @model_status if the type is worse than @model_status' do
323
- model.fake_an_alert(:warning, :price, 'xoo')
297
+ it "sets @model_status if the type is worse than @model_status" do
298
+ model.fake_an_alert(:warning, :price, "xoo")
324
299
  expect( model.model_status ).to eq :warning
325
300
 
326
- model.fake_an_alert(:success, :price, 'flom')
301
+ model.fake_an_alert(:success, :price, "flom")
327
302
  expect( model.model_status ).to eq :warning
328
303
 
329
- model.fake_an_alert(:info, :price, 'flom')
304
+ model.fake_an_alert(:info, :price, "flom")
330
305
  expect( model.model_status ).to eq :warning
331
306
 
332
- model.fake_an_alert(:error, :price, 'qar')
307
+ model.fake_an_alert(:error, :price, "qar")
333
308
  expect( model.model_status ).to eq :error
334
309
 
335
- model.fake_an_alert(:warning, :price, 'drazq')
310
+ model.fake_an_alert(:warning, :price, "drazq")
336
311
  expect( model.model_status ).to eq :error
337
312
  end
338
313
 
339
- it 'ignores a new alert if identical to an existing one' do
340
- lurch = 'Dnhhhhhh'
314
+ it "ignores a new alert if identical to an existing one" do
315
+ lurch = "Dnhhhhhh"
341
316
  2.times { model.fake_an_alert(:error, :price, lurch) }
342
317
 
343
318
  expect( model.alerts.size ).to eq 1
344
319
  end
345
320
 
346
- end
347
- ##
348
-
321
+ end # of #add_alert
349
322
 
350
- describe '#set' do
351
323
 
324
+ describe "#set" do
352
325
  let (:ot) { records_as_ot[3] }
353
326
 
354
- it 'takes an Octothorpe or a Hash' do
327
+ it "takes an Octothorpe or a Hash" do
355
328
  expect{ model.set }.to raise_exception ArgumentError
356
329
  expect{ model.set(nil) }.to raise_exception ArgumentError
357
330
  expect{ model.set(:foo) }.to raise_exception ArgumentError
@@ -359,11 +332,11 @@ describe 'CustomerModel' do
359
332
  expect{ model.set(ot) }.not_to raise_exception
360
333
  end
361
334
 
362
- it 'returns self' do
335
+ it "returns self" do
363
336
  expect( model.set(ot) ).to eq model
364
337
  end
365
338
 
366
- it 'sets the attribute columns from the hash' do
339
+ it "sets the attribute columns from the hash" do
367
340
  model.set(ot)
368
341
 
369
342
  expect( model.id ).to eq ot.>>.id
@@ -371,270 +344,244 @@ describe 'CustomerModel' do
371
344
  expect( model.price ).to eq ot.>>.price
372
345
  end
373
346
 
374
- it 'only sets the attributes on the model that it is given' do
375
- otx = Octothorpe.new(name: 'Piggy', price: 98.76, weapon: 'rake')
347
+ it "only sets the attributes on the model that it is given" do
348
+ otx = Octothorpe.new(name: "Piggy", price: 98.76, weapon: "rake")
376
349
 
377
350
  expect{ model3.set(otx) }.not_to raise_exception
378
- expect( model3.id ).to eq 40
379
- expect( model3.name ).to eq 'Piggy'
351
+ expect( model3.id ).to eq 4
352
+ expect( model3.name ).to eq "Piggy"
380
353
  expect( model3.price ).to eq 98.76
381
- expect( model3.groups ).to eq( ot.>>.groups.split(',') )
354
+ expect( model3.groups ).to eq( ot.>>.groups.split(",") )
382
355
  end
383
356
 
384
- end
385
- ##
357
+ end # of #set
386
358
 
387
359
 
388
- describe '#to_ot' do
389
- it 'returns an Octothorpe made of the attribute columns' do
390
- expect( model.to_ot ).to be_a_kind_of Octothorpe
360
+ describe "#to_ot" do
391
361
 
392
- expect( model.to_ot.to_h ).
393
- to eq( {id: nil, name: nil, price:nil, groups:nil} )
362
+ it "returns an Octothorpe made of the attribute columns, including the ID field" do
363
+ m1 = customer_model_class.new
364
+ expect( m1.to_ot ).to be_a_kind_of Octothorpe
365
+ expect( m1.to_ot.to_h ).to eq( {id: nil, name: nil, price:nil, groups:nil} )
394
366
 
395
- model.map_to_model(records[1])
396
- expect( model.to_ot ).to be_a_kind_of Octothorpe
397
- expect( without_groups(model.to_ot) ).to eq recordsx[1]
367
+ m2 = customer_model_class.new(1)
368
+ m2.read
369
+ expect( m2.to_ot ).to be_a_kind_of Octothorpe
370
+ expect( without_groups(m2.to_ot) ).to eq recordsx[0]
398
371
 
399
- model.map_to_model(records_as_ot[2])
400
- expect( model.to_ot ).to be_a_kind_of Octothorpe
401
- expect( without_groups(model.to_ot) ).to eq recordsx[2]
372
+ m3 = customer_model_class.new(2)
373
+ m3.read
374
+ expect( m3.to_ot ).to be_a_kind_of Octothorpe
375
+ expect( without_groups(m3.to_ot) ).to eq recordsx[1]
402
376
  end
403
- end
404
- ##
377
+
378
+ end # of #to_ot
405
379
 
406
380
 
407
- describe '#map_to_model' do
381
+ describe "#map_to_model" do
382
+
383
+ it "sets the columns, with groups as an array" do
384
+ # testing the custom typecasting in customer_model_class
408
385
 
409
- it 'sets the columns, with groups as an array' do
410
386
  cm = customer_model_class.new
411
387
  cm.map_to_model(records.last)
412
388
 
413
- expect( cm.groups ).to eq( ['trains','school'] )
389
+ expect( cm.groups ).to eq( ["trains","school"] )
414
390
  end
415
391
 
416
- end
417
- ##
392
+ end # of #map_to_model
393
+
418
394
 
395
+ describe "#map_to_interface" do
419
396
 
420
- describe '#map_to_interface' do
397
+ it "returns the columns, with groups as a list" do
398
+ # testing the custom typecasting in customer_model_class
421
399
 
422
- it 'returns the columns, with groups as a list' do
423
400
  cm = customer_model_class.new
424
401
  cm.map_to_model(records.last)
425
402
 
426
- expect( cm.map_to_interface.>>.groups ).to eq( 'trains,school' )
403
+ expect( cm.map_to_interface ).to be_an Octothorpe
404
+ expect( cm.map_to_interface.>>.groups ).to eq( "trains,school" )
427
405
  end
428
406
 
429
- end
430
- ##
407
+ end # of #map_to_interface
431
408
 
432
409
 
433
- describe '#raise_exceptions' do
410
+ describe "#raise_exceptions" do
434
411
 
435
- it 'is also known as .or_die' do
412
+ it "is also known as .or_die" do
436
413
  cm = customer_model_class.new
437
414
  expect( cm.method(:raise_exceptions) ).to eq( cm.method(:or_die) )
438
415
  end
439
416
 
440
- it 'raises ValidationError if model status is :error' do
441
- model.fake_an_alert(:error, :price, 'qar')
417
+ it "raises ValidationError if model status is :error" do
418
+ model.fake_an_alert(:error, :price, "qar")
442
419
  expect{ model.raise_exceptions }.to raise_exception Pod4::ValidationError
443
420
  end
444
421
 
445
- it 'does nothing if model status is not :error' do
422
+ it "does nothing if model status is not :error" do
446
423
  expect{ model.raise_exceptions }.not_to raise_exception
447
424
 
448
- model.fake_an_alert(:info, :price, 'qar')
425
+ model.fake_an_alert(:info, :price, "qar")
449
426
  expect{ model.raise_exceptions }.not_to raise_exception
450
427
 
451
- model.fake_an_alert(:success, :price, 'qar')
428
+ model.fake_an_alert(:success, :price, "qar")
452
429
  expect{ model.raise_exceptions }.not_to raise_exception
453
430
 
454
- model.fake_an_alert(:warning, :price, 'qar')
431
+ model.fake_an_alert(:warning, :price, "qar")
455
432
  expect{ model.raise_exceptions }.not_to raise_exception
456
433
  end
457
434
 
458
- end
459
- ##
460
-
435
+ end # of #raise_exceptions
461
436
 
462
- describe '#create' do
463
437
 
438
+ describe "#create" do
464
439
  let (:new_model) { customer_model_class.new }
465
440
 
466
- it 'takes no parameters' do
441
+ it "takes no parameters" do
467
442
  expect{ customer_model_class.new.create(12) }.to raise_exception ArgumentError
468
443
  expect{ customer_model_class.new.create }.not_to raise_exception
469
444
  end
470
445
 
471
- it 'returns self' do
446
+ it "returns self" do
472
447
  expect( new_model.create ).to eq new_model
473
448
  end
474
449
 
475
- it 'calls validate' do
476
- # validation tests arity of the validate method; rspec freaks out. So we can't
477
- # `expect( new_model ).to receive(:validate)`
450
+ it "calls validate and passes the parameter" do
451
+ expect( new_model ).to receive(:validate).with(:create)
478
452
 
479
- m = customer_model_class.new
480
- m.name = "fall over"
481
- m.create
482
- expect( m.model_status ).to eq :error
453
+ new_model.name = "foo"
454
+ new_model.create
483
455
  end
484
456
 
485
- it 'calls create on the interface if the record is good' do
457
+ it "calls create on the interface if the record is good" do
486
458
  expect( customer_model_class.interface ).to receive(:create)
487
459
  customer_model_class.new.create
488
460
 
489
- new_model.fake_an_alert(:warning, :name, 'foo')
461
+ new_model.fake_an_alert(:warning, :name, "foo")
490
462
  expect( new_model.interface ).to receive(:create)
491
463
  new_model.create
492
464
  end
493
465
 
494
-
495
- it 'doesnt call create on the interface if the record is bad' do
496
- new_model.fake_an_alert(:error, :name, 'foo')
466
+ it "doesn't call create on the interface if the record is bad" do
467
+ new_model.fake_an_alert(:error, :name, "foo")
497
468
  expect( new_model.interface ).not_to receive(:create)
498
469
  new_model.create
499
470
  end
500
471
 
501
- it 'sets the ID' do
502
- new_model.id = 50
503
- new_model.name = "Lurch"
504
- new_model.create
505
-
506
- expect( new_model.model_id ).to eq 50
507
- end
508
-
509
- it 'sets model status to :okay if it was :empty' do
510
- new_model.id = 50
472
+ it "sets model status to :okay if it was :unknown" do
473
+ new_model.id = 5
511
474
  new_model.name = "Lurch"
512
475
  new_model.create
513
476
 
514
477
  expect( new_model.model_status ).to eq :okay
515
478
  end
516
479
 
517
- it 'leaves the model status alone if it was not :empty' do
518
- new_model.id = 50
480
+ it "leaves the model status alone if it was not :unknown" do
481
+ new_model.id = 5
519
482
  new_model.name = "Lurch"
520
483
  new_model.create
521
484
 
522
- new_model.fake_an_alert(:warning, :price, 'qar')
485
+ new_model.fake_an_alert(:warning, :price, "qar")
523
486
  expect( new_model.model_status ).to eq :warning
524
487
  end
525
488
 
526
- it 'calls map_to_interface to get record data' do
527
- allow( new_model.interface ).to receive(:create)
528
- expect( new_model ).to receive(:map_to_interface)
489
+ it "calls map_to_interface to get record data" do
490
+ m = customer_model_class.new
529
491
 
530
- new_model.id = 50
531
- new_model.name = "Lurch"
532
- new_model.create
533
- end
492
+ expect( m ).to receive(:map_to_interface).and_call_original
534
493
 
535
- it 'doesn\'t freak out if the model is not an integer' do
536
- expect( new_model.interface ).to receive(:create)
537
- new_model.id = "handy"
538
- new_model.name = "Thing"
494
+ m.id = 5
495
+ m.name = "Lurch"
496
+ m.create
497
+ end
539
498
 
540
- expect{ new_model.create }.not_to raise_error
499
+ it "doesn't freak out if the ID field (non-autoincrementing) is not an integer" do
500
+ m = product_model_class.new("baz").read
501
+ m.level = 99
502
+ expect{ m.create }.not_to raise_error
541
503
  end
542
504
 
543
505
  it "creates an alert instead when the interface raises WeakError" do
544
506
  allow( new_model.interface ).to receive(:create).and_raise Pod4::WeakError, "foo"
545
507
 
546
- new_model.id = 50
508
+ new_model.id = 5
547
509
  new_model.name = "Lurch"
548
510
  expect{ new_model.create }.not_to raise_exception
549
511
  expect( new_model.model_status ).to eq :error
550
512
  expect( new_model.alerts.map(&:message) ).to include( include "foo" )
551
513
  end
552
514
 
553
- end
554
- ##
515
+ it "updates @model_id" do
516
+ m = customer_model_class.new
517
+ m.id = 5
518
+ m.name = "Lurch"
519
+ m.create
520
+
521
+ expect( m.model_id ).to eq 5
522
+ end
523
+
524
+ end # of #create
555
525
 
556
526
 
557
- describe '#read' do
527
+ describe "#read" do
558
528
 
559
- it 'takes no parameters' do
529
+ it "takes no parameters" do
560
530
  expect{ customer_model_class.new.create(12) }.to raise_exception ArgumentError
561
531
  expect{ customer_model_class.new.create }.not_to raise_exception
562
532
  end
563
533
 
564
- it 'returns self ' do
565
- allow( model.interface ).
566
- to receive(:read).
567
- and_return( records_as_ot.first )
568
-
534
+ it "returns self" do
569
535
  expect( model.read ).to eq model
570
536
  end
571
537
 
572
- it 'calls read on the interface' do
573
- expect( model.interface ).
574
- to receive(:read).
575
- and_return( records_as_ot.first )
576
-
538
+ it "calls read on the interface" do
539
+ expect( model.interface ).to receive(:read).with(2).and_call_original
577
540
  model.read
578
541
  end
579
542
 
580
- it 'calls validate' do
581
- # again, because rspec is a bit stupid, we can't just `expect(model).to receive(:validate)`
582
-
583
- allow( model.interface ).
584
- to receive(:read).
585
- and_return( records_as_ot.first.merge(name: "fall over") )
586
-
543
+ it "calls validate and passes the parameter" do
544
+ expect( model ).to receive(:validate).with(:read)
587
545
  model.read
588
- expect( model.model_status ).to eq :error
589
546
  end
590
547
 
591
- it 'sets the attribute columns using map_to_model' do
548
+ it "sets the attribute columns using map_to_model" do
592
549
  ot = records_as_ot.last
593
- allow( model.interface ).to receive(:read).and_return( ot )
594
-
595
- cm = customer_model_class.new(10).read
596
- expect( cm.id ).to eq ot.>>.id
550
+ cm = customer_model_class.new(4).read
597
551
  expect( cm.name ).to eq ot.>>.name
598
552
  expect( cm.price ).to eq ot.>>.price
599
553
  expect( cm.groups ).to be_a_kind_of(Array)
600
- expect( cm.groups ).to eq( ot.>>.groups.split(',') )
554
+ expect( cm.groups ).to eq( ot.>>.groups.split(",") )
601
555
  end
602
556
 
603
- it 'sets model status to :okay if it was :empty' do
557
+ it "sets model status to :okay if it was :unknown" do
604
558
  ot = records_as_ot.last
605
- allow( model.interface ).to receive(:read).and_return( ot )
606
-
607
559
  model.read
608
560
  expect( model.model_status ).to eq :okay
609
561
  end
610
562
 
611
- it 'leaves the model status alone if it was not :empty' do
563
+ it "leaves the model status alone if it was not :unknown" do
612
564
  ot = records_as_ot.last
613
- allow( model.interface ).to receive(:read).and_return( ot )
614
-
615
- model.fake_an_alert(:warning, :price, 'qar')
565
+ model.fake_an_alert(:warning, :price, "qar")
616
566
  model.read
617
567
  expect( model.model_status ).to eq :warning
618
568
  end
619
569
 
620
- it 'doesn\'t freak out if the model is non-integer' do
621
- allow( model.interface ).to receive(:read).and_return( thing )
622
-
623
- expect{ customer_model_class.new('eek').read }.not_to raise_error
570
+ it "doesn't freak out if the (non-autoincrementing) ID is non-integer" do
571
+ expect{ product_model_class.new("foo").read }.not_to raise_error
624
572
  end
625
573
 
626
- context 'if the interface.read returns an empty Octothorpe' do
574
+ context "if the interface.read returns an empty Octothorpe" do
627
575
  let(:missing) { customer_model_class.new(99) }
628
576
 
629
- it 'doesn\'t throw an exception' do
577
+ it "doesn't throw an exception" do
630
578
  expect{ missing.read }.not_to raise_exception
631
579
  end
632
580
 
633
- it 'raises an error alert' do
581
+ it "raises an error alert" do
634
582
  expect( missing.read.model_status ).to eq :error
635
583
  expect( missing.read.alerts.first.type ).to eq :error
636
584
  end
637
-
638
585
  end
639
586
 
640
587
  it "creates an alert instead when the interface raises WeakError" do
@@ -645,86 +592,74 @@ describe 'CustomerModel' do
645
592
  expect( model.alerts.map(&:message) ).to include( include "foo" )
646
593
  end
647
594
 
648
- end
649
- ##
595
+ it "updates @model_id" do
596
+ foo = product_model_class.new("foo")
597
+ foo.read
650
598
 
599
+ expect( foo.model_id ).to eq "foo"
600
+ end
651
601
 
652
- describe '#update' do
602
+ end # of #read
653
603
 
654
- before do
655
- allow( model2.interface ).
656
- to receive(:update).
657
- and_return( model2.interface )
658
604
 
659
- end
605
+ describe "#update" do
660
606
 
661
- it 'takes no parameters' do
607
+ it "takes no parameters" do
662
608
  expect{ model2.update(12) }.to raise_exception ArgumentError
663
609
  expect{ model2.update }.not_to raise_exception
664
610
  end
665
611
 
666
- it 'returns self' do
612
+ it "returns self" do
667
613
  expect( model2.update ).to eq model2
668
614
  end
669
615
 
670
- it 'raises a Pod4Error if model status is :empty' do
671
- allow( model.interface ).to receive(:update).and_return( model.interface )
672
-
673
- expect( model.model_status ).to eq :empty
616
+ it "raises a Pod4Error if model status is :unknown" do
617
+ expect( model.model_status ).to eq :unknown
674
618
  expect{ model.update }.to raise_exception Pod4::Pod4Error
675
619
  end
676
620
 
677
- it 'raises a Pod4Error if model status is :deleted' do
621
+ it "raises a Pod4Error if model status is :deleted" do
678
622
  model2.delete
679
623
  expect{ model2.update }.to raise_exception Pod4::Pod4Error
680
624
  end
681
625
 
682
- it 'calls validate' do
683
- # again, we can't `expect(model2).to receive(:validate)` because we're testing arity there
684
- model2.name = "fall over"
626
+ it "calls validate and passes the parameter" do
627
+ expect( model2 ).to receive(:validate).with(:update)
628
+
629
+ model2.name = "foo"
685
630
  model2.update
686
- expect( model2.model_status ).to eq :error
687
631
  end
688
632
 
689
- it 'calls update on the interface if the validation passes' do
690
- expect( model3.interface ).
691
- to receive(:update).
692
- and_return( model3.interface )
633
+ it "calls update on the interface if the validation passes" do
634
+ expect( model3.interface ).to receive(:update)
693
635
 
694
636
  model3.update
695
637
  end
696
638
 
697
- it 'doesn\'t call update on the interface if the validation fails' do
639
+ it "doesn't call update on the interface if the validation fails" do
698
640
  expect( model3.interface ).not_to receive(:update)
699
641
 
700
642
  model3.name = "fall over" # triggers validation
701
643
  model3.update
702
644
  end
703
645
 
704
- it 'calls map_to_interface to get record data' do
646
+ it "calls map_to_interface to get record data" do
705
647
  expect( model3 ).to receive(:map_to_interface)
706
648
  model3.update
707
649
  end
708
650
 
709
- it 'doesn\'t freak out if the model is non-integer' do
710
- expect( model4.interface ).
711
- to receive(:update).
712
- and_return( model4.interface )
713
-
714
- model4.update
651
+ it "doesn't freak out if the (non_autoincrementing) ID is non-integer" do
652
+ m = product_model_class.new("bar").read
653
+ expect{ m.update }.not_to raise_error
715
654
  end
716
655
 
717
- context 'when the record already has error alerts' do
718
-
719
- it 'passes if there is no longer anything wrong' do
720
- expect( model3.interface ).
721
- to receive(:update).
722
- and_return( model3.interface )
656
+ context "when the record already has error alerts" do
657
+ it "passes if there is no longer anything wrong" do
658
+ expect( model3.interface ).to receive(:update)
723
659
 
724
660
  model3.fake_an_alert(:error, "bad things")
725
661
  model3.update
726
662
  end
727
-
728
663
  end
729
664
 
730
665
  it "creates an alert instead when the interface raises WeakError" do
@@ -735,70 +670,59 @@ describe 'CustomerModel' do
735
670
  expect( model3.alerts.map(&:message) ).to include( include "foo" )
736
671
  end
737
672
 
738
- end
739
- ##
740
-
673
+ it "updates @model_id" do
674
+ foo = product_model_class.new("foo").read
675
+ foo.code = "bang"
676
+ foo.update
677
+
678
+ expect( foo.model_id ).to eq "bang"
679
+ end
741
680
 
742
- describe '#delete' do
681
+ end # of #update
743
682
 
744
- before do
745
- allow( model2.interface ).
746
- to receive(:delete).
747
- and_return( model2.interface )
748
683
 
749
- end
684
+ describe "#delete" do
750
685
 
751
- it 'takes no parameters' do
686
+ it "takes no parameters" do
752
687
  expect{ model2.delete(12) }.to raise_exception ArgumentError
753
688
  expect{ model2.delete }.not_to raise_exception
754
689
  end
755
690
 
756
- it 'returns self' do
691
+ it "returns self" do
757
692
  expect( model2.delete ).to eq model2
758
693
  end
759
694
 
760
- it 'raises a Pod4Error if model status is :empty' do
761
- allow( model.interface ).to receive(:delete).and_return( model.interface )
762
-
763
- expect( model.model_status ).to eq :empty
695
+ it "raises a Pod4Error if model status is :unknown" do
696
+ expect( model.model_status ).to eq :unknown
764
697
  expect{ model.delete }.to raise_exception Pod4::Pod4Error
765
698
  end
766
699
 
767
- it 'raises a Pod4Error if model status is :deleted'do
700
+ it "raises a Pod4Error if model status is :deleted"do
768
701
  model2.delete
769
702
  expect{ model2.delete }.to raise_exception Pod4::Pod4Error
770
703
  end
771
704
 
772
- it 'calls validate' do
773
- # again, because rspec can't cope with us testing arity in Pod4::Model, we can't say
774
- # `expect(model2).to receive(:validate)`. But for delete we are only running validation as a
775
- # courtesy -- a validation fail does not stop the delete, it just sets alerts. So the model
776
- # status should be :deleted and not :error
777
- model2.name = "fall over"
705
+ it "calls validate and passes the parameter" do
706
+ expect( model2 ).to receive(:validate).with(:delete)
778
707
  model2.delete
779
-
780
- # one of the elements of the alerts array should include the word "falling"
781
- expect( model2.alerts.map(&:message) ).to include(include "falling")
782
708
  end
783
709
 
784
- it 'calls delete on the interface if the model status is good' do
710
+ it "calls delete on the interface if the model status is good" do
785
711
  expect( model3.interface ).
786
- to receive(:delete).
787
- and_return( model3.interface )
712
+ to receive(:delete)
788
713
 
789
714
  model3.delete
790
715
  end
791
716
 
792
- it 'calls delete on the interface if the model status is bad' do
717
+ it "calls delete on the interface if the model status is bad" do
793
718
  expect( model3.interface ).
794
- to receive(:delete).
795
- and_return( model3.interface )
719
+ to receive(:delete)
796
720
 
797
- model3.fake_an_alert(:error, :price, 'qar')
721
+ model3.fake_an_alert(:error, :price, "qar")
798
722
  model3.delete
799
723
  end
800
724
 
801
- it 'still gives you full access to the data after a delete' do
725
+ it "still gives you full access to the data after a delete" do
802
726
  model2.delete
803
727
 
804
728
  expect( model2.id ).to eq records_as_ot[2].>>.id
@@ -806,17 +730,14 @@ describe 'CustomerModel' do
806
730
  expect( model2.price ).to eq records_as_ot[2].>>.price
807
731
  end
808
732
 
809
- it 'sets status to :deleted' do
733
+ it "sets status to :deleted" do
810
734
  model2.delete
811
735
  expect( model2.model_status ).to eq :deleted
812
736
  end
813
737
 
814
- it 'doesn\'t freak out if the model is non-integer' do
815
- expect( model4.interface ).
816
- to receive(:delete).
817
- and_return( model4.interface )
818
-
819
- model4.delete
738
+ it "doesn't freak out if the (non-autoincrementing) ID is non-integer" do
739
+ m = product_model_class.new("bar").read
740
+ expect{ m.delete }.not_to raise_error
820
741
  end
821
742
 
822
743
  it "creates an alert instead when the interface raises WeakError" do
@@ -826,8 +747,7 @@ describe 'CustomerModel' do
826
747
  expect( model3.alerts.map(&:message) ).to include( include "foo" )
827
748
  end
828
749
 
829
- end
830
- ##
750
+ end # of #delete
831
751
 
832
752
  end
833
753