pod4 0.8.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.hgtags +1 -0
- data/.ruby-version +1 -1
- data/Gemfile +5 -5
- data/lib/pod4/errors.rb +5 -0
- data/lib/pod4/nebulous_interface.rb +10 -11
- data/lib/pod4/pg_interface.rb +2 -2
- data/lib/pod4/tds_interface.rb +4 -2
- data/lib/pod4/typecasting.rb +1 -1
- data/lib/pod4/version.rb +1 -1
- data/pod4.gemspec +1 -21
- data/spec/common/basic_model_spec.rb +37 -45
- data/spec/common/model_plus_typecasting_spec.rb +16 -16
- data/spec/common/model_spec.rb +96 -103
- data/spec/common/nebulous_interface_spec.rb +78 -74
- data/spec/common/sequel_interface_pg_spec.rb +23 -19
- data/spec/common/sql_helper_spec.rb +24 -14
- data/spec/jruby/sequel_interface_jdbc_ms_spec.rb +24 -17
- data/spec/jruby/sequel_interface_jdbc_pg_spec.rb +30 -4
- data/spec/mri/pg_interface_spec.rb +50 -41
- data/spec/mri/sequel_interface_spec.rb +48 -53
- data/spec/mri/tds_interface_spec.rb +51 -42
- data/tags +186 -47
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f29b0bd813bbf2094177505acbaea2c3f53fdaa
|
4
|
+
data.tar.gz: 869b71281afe127ed15230298bfad61e070e77d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b33eaf931088d4d31ad52d560d8a45b969eb402a3c9baf4d22ec8c8bed017cca67de1ee001c23c6625200ee8f6d0c86107ada232e027c4134a69c9c7e73527c7
|
7
|
+
data.tar.gz: dc7a67002ffcd2c3f7911d18e5bbb131c36c41c630ed7ee2c91c6d461d98caafaa2a500877914eec66d90475201a9420b44952ba355265c4990c5db42888b2e1
|
data/.hgtags
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.3.
|
1
|
+
2.3.2
|
data/Gemfile
CHANGED
@@ -6,15 +6,15 @@ gemspec
|
|
6
6
|
group :development, :test do
|
7
7
|
|
8
8
|
# for bundler, management, etc etc
|
9
|
-
gem "bundler", "~> 1.
|
10
|
-
gem "rake", "~>
|
11
|
-
gem "rspec", "~> 3.
|
9
|
+
gem "bundler", "~> 1.13"
|
10
|
+
gem "rake", "~> 12.0"
|
11
|
+
gem "rspec", "~> 3.5"
|
12
12
|
gem 'pry'
|
13
13
|
gem "pry-doc"
|
14
14
|
|
15
15
|
# For testing
|
16
|
-
gem "sequel", "~> 4.
|
17
|
-
gem "nebulous_stomp", "~>
|
16
|
+
gem "sequel", "~> 4.41"
|
17
|
+
gem "nebulous_stomp", "~> 3"
|
18
18
|
|
19
19
|
platforms :ruby do
|
20
20
|
gem "sqlite3", "~> 1.3"
|
data/lib/pod4/errors.rb
CHANGED
@@ -57,7 +57,7 @@ module Pod4
|
|
57
57
|
|
58
58
|
attr_reader :id_fld
|
59
59
|
|
60
|
-
# The
|
60
|
+
# The NebulousStomp Message object holding the response from the last message sent, or, nil.
|
61
61
|
attr_reader :response
|
62
62
|
|
63
63
|
# The status of the response from the last message:
|
@@ -153,10 +153,10 @@ module Pod4
|
|
153
153
|
##
|
154
154
|
# In normal operation, takes no parameters.
|
155
155
|
#
|
156
|
-
# For testing purposes you may pass
|
157
|
-
#
|
158
|
-
#
|
159
|
-
# called instead of creating a
|
156
|
+
# For testing purposes you may pass something here. Whatever it is you pass, it must respond to
|
157
|
+
# a `send` method, take the same parameters as NebulousStomp::Request.new (that is, a target
|
158
|
+
# and a message) and return something that behaves like a NebulousStomp::Request. This method
|
159
|
+
# will be called instead of creating a NebulousStomp::Request directly.
|
160
160
|
#
|
161
161
|
def initialize(requestObj=nil)
|
162
162
|
@request_object = requestObj # might as well be a reference
|
@@ -184,9 +184,7 @@ module Pod4
|
|
184
184
|
end
|
185
185
|
|
186
186
|
send_message( verb_for(:list), sel )
|
187
|
-
|
188
|
-
@response.body_to_h # should be an array irrespective of the method name
|
189
|
-
.map{|e| Octothorpe.new(e) }
|
187
|
+
@response.body.is_a?(Array) ? @response.body.map{|e| Octothorpe.new e} : []
|
190
188
|
|
191
189
|
rescue => e
|
192
190
|
handle_error(e)
|
@@ -219,7 +217,7 @@ module Pod4
|
|
219
217
|
|
220
218
|
send_message( verb_for(:read), param_string(:read, nil, id) )
|
221
219
|
|
222
|
-
Octothorpe.new( @response.
|
220
|
+
Octothorpe.new( @response.body.is_a?(Hash) ? @response.body : {} )
|
223
221
|
end
|
224
222
|
|
225
223
|
|
@@ -365,11 +363,12 @@ module Pod4
|
|
365
363
|
# returns the response to the request.
|
366
364
|
#
|
367
365
|
def send_message_helper(verb, paramStr, with_cache)
|
366
|
+
message = NebulousStomp::Message.new(verb: verb, params: paramStr)
|
368
367
|
request =
|
369
368
|
if @request_object
|
370
|
-
@request_object.send(
|
369
|
+
@request_object.send(self.class.target, message)
|
371
370
|
else
|
372
|
-
NebulousStomp::
|
371
|
+
NebulousStomp::Request.new(self.class.target, message)
|
373
372
|
end
|
374
373
|
|
375
374
|
if @clear_cache
|
data/lib/pod4/pg_interface.rb
CHANGED
@@ -139,9 +139,9 @@ module Pod4
|
|
139
139
|
|
140
140
|
rescue => e
|
141
141
|
# Select has already wrapped the error in a Pod4Error, but in this case we want to catch
|
142
|
-
# something
|
142
|
+
# something. Ruby 2.0 doesn't define Exception.cause, but in that case, we do on Pod4Error.
|
143
143
|
raise CantContinue, "That doesn't look like an ID" \
|
144
|
-
if e.cause.class == PG::InvalidTextRepresentation
|
144
|
+
if e.respond_to?(:cause) && e.cause.class == PG::InvalidTextRepresentation
|
145
145
|
|
146
146
|
handle_error(e)
|
147
147
|
end
|
data/lib/pod4/tds_interface.rb
CHANGED
@@ -171,9 +171,11 @@ module Pod4
|
|
171
171
|
|
172
172
|
rescue => e
|
173
173
|
# select already wrapped any error in a Pod4::DatabaseError, but in this case we want to try
|
174
|
-
# to catch something.
|
174
|
+
# to catch something. Ruby 2.0 doesn't define Exception.cause, but if it doesn't, we do in
|
175
|
+
# Pod4Error, so. (Side note: TinyTds' error class structure is a bit poor...)
|
175
176
|
raise CantContinue, "Problem reading record. Is '#{id}' really an ID?" \
|
176
|
-
if e.cause
|
177
|
+
if e.respond_to?(:cause) \
|
178
|
+
&& e.cause.class == TinyTds::Error \
|
177
179
|
&& e.cause.message =~ /conversion failed/i
|
178
180
|
|
179
181
|
|
data/lib/pod4/typecasting.rb
CHANGED
data/lib/pod4/version.rb
CHANGED
data/pod4.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.authors = ["Andy Jones"]
|
9
9
|
spec.email = ["andy.jones@twosticksconsulting.co.uk"]
|
10
10
|
spec.summary = %q|Totally not an ORM|
|
11
|
-
spec.description =
|
11
|
+
spec.description = <<-DESC.gsub(/^\s+/, "")
|
12
12
|
Provides a simple, common framework to talk to a bunch of data sources,
|
13
13
|
using model classes which consist of a bare minimum of DSL plus vanilla Ruby
|
14
14
|
inheritance.
|
@@ -27,24 +27,4 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_runtime_dependency "devnull", '~>0.1'
|
28
28
|
spec.add_runtime_dependency "octothorpe", '~>0.3'
|
29
29
|
|
30
|
-
=begin
|
31
|
-
# for bundler, management, etc etc
|
32
|
-
spec.add_development_dependency "bundler", "~> 1.11"
|
33
|
-
spec.add_development_dependency "rake", "~> 10.5"
|
34
|
-
spec.add_development_dependency "rspec", "~> 3.4"
|
35
|
-
spec.add_development_dependency "rdoc"
|
36
|
-
|
37
|
-
# For testing
|
38
|
-
spec.add_development_dependency "sequel", "~> 4.35"
|
39
|
-
spec.add_development_dependency "sqlite3", "~> 1.3"
|
40
|
-
spec.add_development_dependency "tiny_tds", "~> 0"
|
41
|
-
spec.add_development_dependency "pg", "~> 0"
|
42
|
-
spec.add_development_dependency "nebulous_stomp" , "~> 2"
|
43
|
-
|
44
|
-
# Development tools
|
45
|
-
spec.add_development_dependency "pry"
|
46
|
-
spec.add_development_dependency "pry-doc"
|
47
|
-
spec.add_development_dependency "ripper-tags"
|
48
|
-
=end
|
49
|
-
|
50
30
|
end
|
@@ -4,45 +4,37 @@ require 'pod4/basic_model'
|
|
4
4
|
require 'pod4/null_interface'
|
5
5
|
|
6
6
|
|
7
|
-
|
8
|
-
# We define a model class to test, since in normal operation we would never use
|
9
|
-
# Model directly, and since it needs an inner Interface.
|
10
|
-
#
|
11
|
-
# We can't use a mock for the interface -- class definitions fall outside the
|
12
|
-
# RSpec DSL as far as I can tell, so I can neither create a mock here or inject
|
13
|
-
# it. Which means we can't mock the interface in the rest of the test either;
|
14
|
-
# any mock we created would not get called.
|
15
|
-
#
|
16
|
-
# But: we want to test that Model calls Interface correctly.
|
17
|
-
#
|
18
|
-
# We do have what appears to be a perfectly sane way of testing. We can define
|
19
|
-
# an inner class based on the genuinely existing, non-mock NullInterface class;
|
20
|
-
# and then define expectations on it. When we do this, Rspec fails to pass the
|
21
|
-
# call on to the object, unless we specifically say `.and_call_original`
|
22
|
-
# instead of `.and_return`.
|
23
|
-
#
|
24
|
-
# This is actually quite nice, but more than a little confusing when you see it
|
25
|
-
# for the first time. Its use isn't spelled out in the RSpec docs AFAICS.
|
26
|
-
#
|
27
|
-
class WeirdModel < Pod4::BasicModel
|
28
|
-
set_interface NullInterface.new(:id, :name, :price, :groups, [])
|
29
|
-
|
30
|
-
def fake_an_alert(*args)
|
31
|
-
add_alert(*args) #protected method
|
32
|
-
end
|
33
|
-
|
34
|
-
def reset_alerts; @alerts = []; end
|
35
|
-
end
|
7
|
+
describe 'WeirdModel' do
|
36
8
|
|
9
|
+
##
|
10
|
+
# We define a model class to test, since in normal operation we would never use Model directly,
|
11
|
+
# and since it needs an inner Interface.
|
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
|
+
let(:weird_model_class) do
|
21
|
+
Class.new Pod4::BasicModel do
|
22
|
+
set_interface NullInterface.new(:id, :name, :price, :groups, [])
|
23
|
+
|
24
|
+
def fake_an_alert(*args)
|
25
|
+
add_alert(*args) #protected method
|
26
|
+
end
|
37
27
|
|
28
|
+
def reset_alerts; @alerts = []; end
|
29
|
+
end
|
30
|
+
end
|
38
31
|
|
39
|
-
|
40
|
-
let(:model) { WeirdModel.new(20) }
|
32
|
+
let(:model) { weird_model_class.new(20) }
|
41
33
|
|
42
34
|
|
43
35
|
describe 'Model.set_interface' do
|
44
36
|
it 'requires an Interface object' do
|
45
|
-
expect(
|
37
|
+
expect( weird_model_class ).to respond_to(:set_interface).with(1).argument
|
46
38
|
end
|
47
39
|
|
48
40
|
# it 'sets interface' - covered by the interface test
|
@@ -52,8 +44,8 @@ describe 'WeirdModel' do
|
|
52
44
|
|
53
45
|
describe 'Model.interface' do
|
54
46
|
it 'is the interface object' do
|
55
|
-
expect(
|
56
|
-
expect(
|
47
|
+
expect( weird_model_class.interface ).to be_a_kind_of NullInterface
|
48
|
+
expect( weird_model_class.interface.id_fld ).to eq :id
|
57
49
|
end
|
58
50
|
end
|
59
51
|
##
|
@@ -62,25 +54,25 @@ describe 'WeirdModel' do
|
|
62
54
|
describe '#new' do
|
63
55
|
|
64
56
|
it 'takes an optional ID' do
|
65
|
-
expect{
|
66
|
-
expect{
|
57
|
+
expect{ weird_model_class.new }.not_to raise_exception
|
58
|
+
expect{ weird_model_class.new(1) }.not_to raise_exception
|
67
59
|
end
|
68
60
|
|
69
61
|
it 'sets the ID attribute' do
|
70
|
-
expect(
|
62
|
+
expect( weird_model_class.new(23).model_id ).to eq 23
|
71
63
|
end
|
72
64
|
|
73
65
|
it 'sets the status to empty' do
|
74
|
-
expect(
|
66
|
+
expect( weird_model_class.new.model_status ).to eq :empty
|
75
67
|
end
|
76
68
|
|
77
69
|
it 'initializes the alerts attribute' do
|
78
|
-
expect(
|
70
|
+
expect( weird_model_class.new.alerts ).to eq([])
|
79
71
|
end
|
80
72
|
|
81
73
|
it 'doesn''t freak out if the ID is not an integer' do
|
82
|
-
expect{
|
83
|
-
expect(
|
74
|
+
expect{ weird_model_class.new("france") }.not_to raise_exception
|
75
|
+
expect( weird_model_class.new("france").model_id ).to eq "france"
|
84
76
|
end
|
85
77
|
|
86
78
|
end
|
@@ -89,8 +81,8 @@ describe 'WeirdModel' do
|
|
89
81
|
|
90
82
|
describe '#interface' do
|
91
83
|
it 'returns the interface set in the class definition, again' do
|
92
|
-
expect(
|
93
|
-
expect(
|
84
|
+
expect( weird_model_class.new.interface ).to be_a_kind_of NullInterface
|
85
|
+
expect( weird_model_class.new.interface.id_fld ).to eq :id
|
94
86
|
end
|
95
87
|
end
|
96
88
|
##
|
@@ -98,7 +90,7 @@ describe 'WeirdModel' do
|
|
98
90
|
|
99
91
|
describe '#alerts' do
|
100
92
|
it 'returns the list of alerts against the model' do
|
101
|
-
cm =
|
93
|
+
cm = weird_model_class.new
|
102
94
|
cm.fake_an_alert(:warning, :foo, 'one')
|
103
95
|
cm.fake_an_alert(:error, :bar, 'two')
|
104
96
|
|
@@ -195,7 +187,7 @@ describe 'WeirdModel' do
|
|
195
187
|
describe '#raise_exceptions' do
|
196
188
|
|
197
189
|
it 'is also known as .or_die' do
|
198
|
-
cm =
|
190
|
+
cm = weird_model_class.new
|
199
191
|
expect( cm.method(:raise_exceptions) ).to eq( cm.method(:or_die) )
|
200
192
|
end
|
201
193
|
|
@@ -5,17 +5,17 @@ require 'pod4/typecasting'
|
|
5
5
|
require 'pod4/null_interface'
|
6
6
|
|
7
7
|
|
8
|
-
class ProductModel < Pod4::Model
|
9
|
-
include Pod4::TypeCasting
|
10
|
-
force_encoding Encoding::ISO_8859_1 # I assume we are running as UTF8 here
|
11
|
-
attr_columns :id, :code, :product, :price
|
12
|
-
set_interface NullInterface.new(:id, :code, :product, :price, [])
|
13
|
-
end
|
14
|
-
|
15
|
-
|
16
|
-
|
17
8
|
describe 'ProductModel' do
|
18
9
|
|
10
|
+
let(:product_model_class) do
|
11
|
+
Class.new Pod4::Model do
|
12
|
+
include Pod4::TypeCasting
|
13
|
+
force_encoding Encoding::ISO_8859_1 # I assume we are running as UTF8 here
|
14
|
+
attr_columns :id, :code, :product, :price
|
15
|
+
set_interface NullInterface.new(:id, :code, :product, :price, [])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
19
|
let(:records) do
|
20
20
|
[ {id: 10, code: 'aa1', product: 'beans', price: 1.23},
|
21
21
|
{id: 20, code: 'bb1', product: 'pears', price: 2.34},
|
@@ -23,10 +23,10 @@ describe 'ProductModel' do
|
|
23
23
|
{id: 40, code: 'cc2', product: 'matches', price: 4.56} ]
|
24
24
|
end
|
25
25
|
|
26
|
-
let(:model) {
|
26
|
+
let(:model) { product_model_class.new(20) }
|
27
27
|
|
28
28
|
let(:model2) do
|
29
|
-
m =
|
29
|
+
m = product_model_class.new(30)
|
30
30
|
|
31
31
|
allow( m.interface ).to receive(:read).
|
32
32
|
and_return( Octothorpe.new(records[2]) )
|
@@ -43,20 +43,20 @@ describe 'ProductModel' do
|
|
43
43
|
describe 'Model.force_encoding' do
|
44
44
|
|
45
45
|
it 'requires an encoding' do
|
46
|
-
expect(
|
46
|
+
expect( product_model_class ).to respond_to(:force_encoding).with(1).argument
|
47
47
|
|
48
|
-
expect{
|
48
|
+
expect{ product_model_class.force_encoding('foo') }.to raise_exception Pod4Error
|
49
49
|
|
50
50
|
# Cheating here: this has to be the same as above or other tests will
|
51
51
|
# fail...
|
52
|
-
expect{
|
52
|
+
expect{ product_model_class.force_encoding(Encoding::ISO_8859_1) }.
|
53
53
|
not_to raise_exception
|
54
54
|
|
55
55
|
end
|
56
56
|
|
57
57
|
it 'sets the encoding to be returned by Model.encoding' do
|
58
|
-
expect{
|
59
|
-
expect(
|
58
|
+
expect{ product_model_class.encoding }.not_to raise_exception
|
59
|
+
expect( product_model_class.encoding ).to eq(Encoding::ISO_8859_1)
|
60
60
|
end
|
61
61
|
|
62
62
|
end
|