pod4 0.6.2
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 +7 -0
- data/.hgignore +18 -0
- data/.hgtags +19 -0
- data/.rspec +4 -0
- data/.ruby-version +1 -0
- data/Gemfile +3 -0
- data/LICENSE.md +21 -0
- data/README.md +556 -0
- data/Rakefile +30 -0
- data/lib/pod4/alert.rb +87 -0
- data/lib/pod4/basic_model.rb +137 -0
- data/lib/pod4/errors.rb +80 -0
- data/lib/pod4/interface.rb +110 -0
- data/lib/pod4/metaxing.rb +66 -0
- data/lib/pod4/model.rb +347 -0
- data/lib/pod4/nebulous_interface.rb +408 -0
- data/lib/pod4/null_interface.rb +148 -0
- data/lib/pod4/param.rb +29 -0
- data/lib/pod4/pg_interface.rb +460 -0
- data/lib/pod4/sequel_interface.rb +303 -0
- data/lib/pod4/tds_interface.rb +394 -0
- data/lib/pod4/version.rb +3 -0
- data/lib/pod4.rb +54 -0
- data/md/fixme.md +32 -0
- data/md/roadmap.md +69 -0
- data/pod4.gemspec +49 -0
- data/spec/README.md +19 -0
- data/spec/alert_spec.rb +173 -0
- data/spec/basic_model_spec.rb +220 -0
- data/spec/doc_no_pending.rb +5 -0
- data/spec/fixtures/database.rb +13 -0
- data/spec/model_spec.rb +760 -0
- data/spec/nebulous_interface_spec.rb +286 -0
- data/spec/null_interface_spec.rb +153 -0
- data/spec/param_spec.rb +89 -0
- data/spec/pg_interface_spec.rb +452 -0
- data/spec/pod4_spec.rb +88 -0
- data/spec/sequel_interface_spec.rb +466 -0
- data/spec/shared_examples_for_interface.rb +160 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/tds_interface_spec.rb +494 -0
- data/tags +106 -0
- metadata +316 -0
@@ -0,0 +1,408 @@
|
|
1
|
+
require 'nebulous'
|
2
|
+
|
3
|
+
require_relative 'interface'
|
4
|
+
require_relative 'errors'
|
5
|
+
|
6
|
+
|
7
|
+
module Pod4
|
8
|
+
|
9
|
+
|
10
|
+
##
|
11
|
+
# An interface to talk to a Nebulous Target.
|
12
|
+
#
|
13
|
+
# Each interface can only speak with one target, designated with #set_target.
|
14
|
+
# The developer must also set a unique ID key using #set_id_fld.
|
15
|
+
#
|
16
|
+
# The primary challenge here is to map the CRUDL methods (which interfaces
|
17
|
+
# contract to implement) to nebulous verbs. The programmer uses #set_verb for
|
18
|
+
# this purpose: the first parameter indicates the CRUDL method, the next is
|
19
|
+
# the verb name, and the rest are hash keys.
|
20
|
+
#
|
21
|
+
# In the case of the #create and #update methods, the list of keys controls
|
22
|
+
# which parts of the incoming hash end up in the verb parameters, and in what
|
23
|
+
# order. For #update, the list must include the ID key that you gave to
|
24
|
+
# #set_id_fld.
|
25
|
+
#
|
26
|
+
# Parameters for the #list method similarly constrain how its selection
|
27
|
+
# parameter is translated to a nebulous verb parameter string.
|
28
|
+
#
|
29
|
+
# Parameters for #read and #delete can be whatever you like, but since the
|
30
|
+
# only value passed to read is the ID, the only symbol there should be the
|
31
|
+
# same as the one in #set_id_fld.
|
32
|
+
#
|
33
|
+
# class CustomerInterface < SwingShift::NebulousInterface
|
34
|
+
# set_target 'accord'
|
35
|
+
# set_id_fld :id
|
36
|
+
# set_verb :read, 'customerread', :id, '100'
|
37
|
+
# set_verb :list, 'customerlist', :name
|
38
|
+
# set_verb :create, 'customerupdate', 'create', :name, :price
|
39
|
+
# set_verb :update, 'customerupdate', 'update', :name, :id, :price
|
40
|
+
#
|
41
|
+
# def update(id, name, price)
|
42
|
+
# super( id, name: name, price: price)
|
43
|
+
# end
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# In this example both the create and update methods point to the same
|
47
|
+
# nebulous verb. Note that only keys which are symbols are translated to the
|
48
|
+
# corresponding values in the record or selection hash; anything else is
|
49
|
+
# passed literally in the Nebulous parameter string.
|
50
|
+
#
|
51
|
+
# When you subclass NebulousInterfce, you may want to override some or all of
|
52
|
+
# the CRUDL methods so that your callers can pass specific parameters rather
|
53
|
+
# than a hash; the above example demonstrates this.
|
54
|
+
#
|
55
|
+
# We assume that the response to the #create message returns the ID as the
|
56
|
+
# parameter part of the success verb. If that's not true, then you will have
|
57
|
+
# to override #create and sort this out yourself.
|
58
|
+
#
|
59
|
+
# Finally, note that all values are returned as strings; there is no
|
60
|
+
# typecasting. This is a given limitation for Nebulous as a whole.
|
61
|
+
#
|
62
|
+
class NebulousInterface < Interface
|
63
|
+
|
64
|
+
attr_reader :id_fld
|
65
|
+
|
66
|
+
# The NebResponse object from the last message sent, or nil otherwise
|
67
|
+
attr_reader :response
|
68
|
+
|
69
|
+
# The status of the response from the last message:
|
70
|
+
# * nil - we didn't send a request yet
|
71
|
+
# * :off - Nebulous is turned off, so nothing happened
|
72
|
+
# * :timeout we sent the message but timed out waiting for a response
|
73
|
+
# * :verberror - we got an error verb in response
|
74
|
+
# * :verbsuccess - we got a success verb in response
|
75
|
+
# * :response - we got some response that doesn't follow The Protocol
|
76
|
+
#
|
77
|
+
# NB: if we got an exception sending the message, we raised it on the
|
78
|
+
# caller, so there is no status for that.
|
79
|
+
attr_reader :response_status
|
80
|
+
|
81
|
+
|
82
|
+
Verb = Struct.new(:name, :params)
|
83
|
+
|
84
|
+
|
85
|
+
class << self
|
86
|
+
#--
|
87
|
+
# These are set in the class because it keeps the model code cleaner: the
|
88
|
+
# definition of the interface stays in the interface, and doesn't leak
|
89
|
+
# out into the model.
|
90
|
+
#++
|
91
|
+
|
92
|
+
##
|
93
|
+
# Set a verb.
|
94
|
+
# * action - must be one of CRUDL
|
95
|
+
# * verb - the name of the verb
|
96
|
+
# * parameters - array of symbols to order the hash passed to create, etc
|
97
|
+
#
|
98
|
+
def set_verb(action, verb, *paramKeys)
|
99
|
+
raise ArgumentError, "Bad action" \
|
100
|
+
unless Interface::ACTIONS.include? action
|
101
|
+
|
102
|
+
v = verbs.dup
|
103
|
+
v[action] = Verb.new( verb, paramKeys.flatten )
|
104
|
+
|
105
|
+
define_class_method(:verbs) {v}
|
106
|
+
end
|
107
|
+
|
108
|
+
def verbs; {}; end
|
109
|
+
|
110
|
+
|
111
|
+
##
|
112
|
+
# Set the name of the Nebulous target in the interface definition
|
113
|
+
#
|
114
|
+
# a reference to the interface object.
|
115
|
+
def set_target(target)
|
116
|
+
define_class_method(:target) {target.to_s}
|
117
|
+
end
|
118
|
+
|
119
|
+
def target
|
120
|
+
raise Pod4Error, "You need to use set_target on your interface"
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
##
|
125
|
+
# Set the name of the ID parameter (needs to be in the CRUD verbs param
|
126
|
+
# list)
|
127
|
+
def set_id_fld(idFld)
|
128
|
+
define_class_method(:id_fld) {idFld}
|
129
|
+
end
|
130
|
+
|
131
|
+
def id_fld
|
132
|
+
raise Pod4Error, "You need to use set_id_fld"
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
##
|
137
|
+
# Make sure all of the above is consistent
|
138
|
+
#
|
139
|
+
def validate_params
|
140
|
+
raise Pod4Error, "You need to use set_verb" if verbs == {}
|
141
|
+
|
142
|
+
%i|create read update delete|.each do |action|
|
143
|
+
raise Pod4Error, "set_verb #{action} is missing a parameter list" \
|
144
|
+
if verbs[action] && !verbs[action].params == []
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
%i|read update delete|.each do |action|
|
149
|
+
raise Pod4Error, "#{action} verb doesn't have an #{id_fld} key" \
|
150
|
+
if verbs[action] && !verbs[action].params.include?(id_fld)
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
end
|
158
|
+
##
|
159
|
+
|
160
|
+
|
161
|
+
##
|
162
|
+
# In normal operation, takes no parameters.
|
163
|
+
#
|
164
|
+
# For testing purposes you may pass an instance of a class here. It must
|
165
|
+
# respond to a #send method with parameters (verb, parameter string, cache
|
166
|
+
# yes/no) by returning some kind of NebRequest (presumably either a double
|
167
|
+
# or an instance of NebRequestNull). This method will be called instead of
|
168
|
+
# creating a NebRequest directly.
|
169
|
+
#
|
170
|
+
def initialize(requestObj=nil)
|
171
|
+
@request_object = requestObj # might as well be a reference
|
172
|
+
@response = nil
|
173
|
+
@response_status = nil
|
174
|
+
@id_fld = self.class.id_fld
|
175
|
+
|
176
|
+
self.class.validate_params
|
177
|
+
end
|
178
|
+
|
179
|
+
|
180
|
+
##
|
181
|
+
# Pass a parameter string or array (which will be taken as the literal
|
182
|
+
# Nebulous parameter) or a Hash or Octothorpe (which will be interpreted as
|
183
|
+
# per your list of keys set in add_verb :list).
|
184
|
+
#
|
185
|
+
# Returns an array of Octothorpes, or an empty array if the responder could
|
186
|
+
# not make any records out of our message.
|
187
|
+
#
|
188
|
+
def list(selection=nil)
|
189
|
+
sel =
|
190
|
+
case selection
|
191
|
+
when Array, Hash, Octothorpe then param_string(:list, selection)
|
192
|
+
else selection
|
193
|
+
end
|
194
|
+
|
195
|
+
send_message( verb_for(:list), sel )
|
196
|
+
|
197
|
+
@response.body_to_h # should be an array irrespective of the method name
|
198
|
+
.map{|e| Octothorpe.new(e) }
|
199
|
+
|
200
|
+
rescue => e
|
201
|
+
handle_error(e)
|
202
|
+
end
|
203
|
+
|
204
|
+
|
205
|
+
##
|
206
|
+
# Pass a parameter string or an array as the record. returns the ID.
|
207
|
+
# We assume that the response to the create message returns the ID as the
|
208
|
+
# parameter part of the success verb. If that's not true, then you will
|
209
|
+
# have to override #create and sort this out yourself.
|
210
|
+
#
|
211
|
+
def create(record)
|
212
|
+
raise ArgumentError, 'create takes a Hash or an Octothorpe' \
|
213
|
+
unless hashy?(record)
|
214
|
+
|
215
|
+
send_message( verb_for(:create), param_string(:create, record) )
|
216
|
+
|
217
|
+
@response.params
|
218
|
+
|
219
|
+
rescue => e
|
220
|
+
handle_error(e)
|
221
|
+
end
|
222
|
+
|
223
|
+
|
224
|
+
##
|
225
|
+
# Given the id, return an Octothorpe of the record.
|
226
|
+
#
|
227
|
+
# The actual parameters passed to nebulous depend on how you #set_verb
|
228
|
+
#
|
229
|
+
def read(id)
|
230
|
+
raise ArgumentError, 'You must pass an ID to read' unless id
|
231
|
+
|
232
|
+
send_message( verb_for(:read), param_string(:read, nil, id) )
|
233
|
+
|
234
|
+
Octothorpe.new( @response.body_to_h )
|
235
|
+
end
|
236
|
+
|
237
|
+
|
238
|
+
##
|
239
|
+
# Given an id an a record (Octothorpe or Hash), update the record. Returns
|
240
|
+
# self.
|
241
|
+
#
|
242
|
+
def update(id, record)
|
243
|
+
raise ArgumentError, 'You must pass an ID to update' unless id
|
244
|
+
raise ArgumentError, 'update record takes a Hash or an Octothorpe' \
|
245
|
+
unless hashy?(record)
|
246
|
+
|
247
|
+
send_message( verb_for(:update),
|
248
|
+
param_string(:update, record, id),
|
249
|
+
false )
|
250
|
+
|
251
|
+
self
|
252
|
+
end
|
253
|
+
|
254
|
+
|
255
|
+
##
|
256
|
+
# Given an ID, delete the record. Return self.
|
257
|
+
#
|
258
|
+
# The actual parameters passed to nebulous depend on how you #set_verb
|
259
|
+
#
|
260
|
+
def delete(id)
|
261
|
+
raise ArgumentError, 'You must pass an ID to delete' unless id
|
262
|
+
|
263
|
+
send_message( verb_for(:delete),
|
264
|
+
param_string(:delete, nil, id),
|
265
|
+
false )
|
266
|
+
|
267
|
+
self
|
268
|
+
end
|
269
|
+
|
270
|
+
|
271
|
+
##
|
272
|
+
# Bonus method: chain this method before a CRUDL method to clear the cache
|
273
|
+
# for that parameter string:
|
274
|
+
# @interface.clearing_cache.read(14)
|
275
|
+
#
|
276
|
+
def clearing_cache
|
277
|
+
@clear_cache = true
|
278
|
+
self
|
279
|
+
end
|
280
|
+
|
281
|
+
|
282
|
+
##
|
283
|
+
# Bonus method: send an arbitrary Nebulous message to the target and return
|
284
|
+
# the response object.
|
285
|
+
#
|
286
|
+
# We don't trap errors here - see #handle_error - but we raise extra ones
|
287
|
+
# if we think things look fishy.
|
288
|
+
#
|
289
|
+
def send_message(verb, paramStr, with_cache=true)
|
290
|
+
unless Nebulous.on?
|
291
|
+
@response_status = :off
|
292
|
+
raise Pod4::DatabaseError, "Nebulous is turned off!"
|
293
|
+
end
|
294
|
+
|
295
|
+
Pod4.logger.debug(__FILE__) do
|
296
|
+
"Sending v:#{verb} p:#{paramStr} c?: #{with_cache}"
|
297
|
+
end
|
298
|
+
|
299
|
+
@response = send_message_helper(verb, paramStr, with_cache)
|
300
|
+
|
301
|
+
raise Pod4::DatabaseError, "Null response" if @response.nil?
|
302
|
+
|
303
|
+
@response_status =
|
304
|
+
case @response.verb
|
305
|
+
when 'error' then :verberror
|
306
|
+
when 'success' then :verbsuccess
|
307
|
+
else :response
|
308
|
+
end
|
309
|
+
|
310
|
+
raise Pod4::CantContinue, "Nebulous returned an error verb" \
|
311
|
+
if @response_status == :verberror
|
312
|
+
|
313
|
+
self
|
314
|
+
|
315
|
+
rescue => err
|
316
|
+
handle_error(err)
|
317
|
+
end
|
318
|
+
|
319
|
+
|
320
|
+
private
|
321
|
+
|
322
|
+
|
323
|
+
##
|
324
|
+
# Given :create, :read, :update, :delete or :list, return the Nebulous verb
|
325
|
+
#
|
326
|
+
def verb_for(action)
|
327
|
+
self.class.verbs[action].name
|
328
|
+
end
|
329
|
+
|
330
|
+
|
331
|
+
##
|
332
|
+
# Work out the parameter string based on the corresponding #set_Verb call.
|
333
|
+
# Insert the ID value if given
|
334
|
+
#
|
335
|
+
def param_string(action, hashParam, id=nil)
|
336
|
+
hash = hashParam ? hashParam.dup : {}
|
337
|
+
|
338
|
+
hash[@id_fld] = id.to_s if id
|
339
|
+
|
340
|
+
para = self.class.verbs[action].params.map do |p|
|
341
|
+
p.kind_of?(Symbol) ? hash[p] : p
|
342
|
+
end
|
343
|
+
|
344
|
+
para.join(',')
|
345
|
+
end
|
346
|
+
|
347
|
+
|
348
|
+
##
|
349
|
+
# Deal with any exceptions that are raised.
|
350
|
+
#
|
351
|
+
# Our contract says that we should throw errors to the model, but those
|
352
|
+
# errors should be Pod4 errors.
|
353
|
+
#
|
354
|
+
def handle_error(err, kaller=caller[1..-1])
|
355
|
+
Pod4.logger.error(__FILE__){ err.message }
|
356
|
+
|
357
|
+
case err
|
358
|
+
when ArgumentError, Pod4::Pod4Error
|
359
|
+
raise err.class, err.message, kaller
|
360
|
+
|
361
|
+
when Nebulous::NebulousTimeout
|
362
|
+
@response_status = :timeout
|
363
|
+
raise Pod4::CantContinue, err.message, kaller
|
364
|
+
|
365
|
+
when Nebulous::NebulousError
|
366
|
+
raise Pod4::DatabaseError, err.message, kaller
|
367
|
+
|
368
|
+
else
|
369
|
+
raise Pod4::Pod4Error, err.message, kaller
|
370
|
+
|
371
|
+
end
|
372
|
+
|
373
|
+
end
|
374
|
+
|
375
|
+
|
376
|
+
##
|
377
|
+
# A little helper method to create a response object (unless we were given
|
378
|
+
# one for testing purposes), clear the cache if we are supposed to, and
|
379
|
+
# then send the message.
|
380
|
+
#
|
381
|
+
# returns the response to the request.
|
382
|
+
#
|
383
|
+
def send_message_helper(verb, paramStr, with_cache)
|
384
|
+
request =
|
385
|
+
if @request_object
|
386
|
+
@request_object.send(verb, paramStr, with_cache)
|
387
|
+
else
|
388
|
+
Nebulous::NebRequest.new(self.class.target, verb, paramStr)
|
389
|
+
end
|
390
|
+
|
391
|
+
if @clear_cache
|
392
|
+
request.clear_cache
|
393
|
+
@clear_cache = false
|
394
|
+
end
|
395
|
+
|
396
|
+
with_cache ? request.send : request.send_no_cache
|
397
|
+
end
|
398
|
+
|
399
|
+
|
400
|
+
def hashy?(obj)
|
401
|
+
obj.kind_of?(Hash) || obj.kind_of?(Octothorpe)
|
402
|
+
end
|
403
|
+
|
404
|
+
|
405
|
+
end
|
406
|
+
|
407
|
+
|
408
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'octothorpe'
|
2
|
+
|
3
|
+
require_relative 'interface'
|
4
|
+
require_relative 'errors'
|
5
|
+
|
6
|
+
|
7
|
+
module Pod4
|
8
|
+
|
9
|
+
|
10
|
+
##
|
11
|
+
# Pod4 Interface *for testing*. Fakes a table and records.
|
12
|
+
#
|
13
|
+
# Example:
|
14
|
+
# class TestModel < Pod4::Model
|
15
|
+
# attr_columns :one, :two
|
16
|
+
# set_interface NullInterface.new( :one, :two [ {one: 1, two: 2} ] )
|
17
|
+
# ...
|
18
|
+
#
|
19
|
+
# The first column passed is taken to be the ID.
|
20
|
+
# Note that ID is not auto-assigned; you need to specify it in the record.
|
21
|
+
#
|
22
|
+
class NullInterface < Interface
|
23
|
+
|
24
|
+
attr_reader :id_fld
|
25
|
+
|
26
|
+
|
27
|
+
##
|
28
|
+
# Initialise the interface by passing it a list of columns and an array of
|
29
|
+
# hashes to fill them.
|
30
|
+
#
|
31
|
+
def initialize(*cols, data)
|
32
|
+
raise ArgumentError, "no columns" if cols.nil? || cols == []
|
33
|
+
|
34
|
+
@cols = cols.dup.map(&:to_sym)
|
35
|
+
@data = Array.new(data.dup).flatten
|
36
|
+
@id_fld = @cols.first
|
37
|
+
|
38
|
+
rescue => e
|
39
|
+
handle_error(e)
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
##
|
44
|
+
# Selection is a hash, but only the first key/value pair is honoured.
|
45
|
+
#
|
46
|
+
def list(selection=nil)
|
47
|
+
if selection
|
48
|
+
key, value = selection.to_a.first
|
49
|
+
rows = @data.find_all {|r| r[key.to_sym] == value}
|
50
|
+
else
|
51
|
+
rows = @data
|
52
|
+
end
|
53
|
+
|
54
|
+
rows.map{|x| Octothorpe.new(x) }
|
55
|
+
|
56
|
+
rescue => e
|
57
|
+
handle_error(e)
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
##
|
62
|
+
# Record is a hash of field: value
|
63
|
+
# Note that we will store any old crap, not just the fields you named in
|
64
|
+
# new().
|
65
|
+
#
|
66
|
+
def create(record)
|
67
|
+
raise(ArgumentError, "Create requires an ID") \
|
68
|
+
if record.nil? || ! record.respond_to?(:to_h)
|
69
|
+
|
70
|
+
@data << record.to_h
|
71
|
+
record[@id_fld]
|
72
|
+
|
73
|
+
rescue => e
|
74
|
+
handle_error(e)
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
##
|
79
|
+
# ID is the first column you named in new()
|
80
|
+
#
|
81
|
+
def read(id)
|
82
|
+
raise(ArgumentError, "Read requires an ID") if id.nil?
|
83
|
+
|
84
|
+
rec = @data.find{|x| x[@id_fld] == id }
|
85
|
+
Octothorpe.new(rec)
|
86
|
+
|
87
|
+
rescue => e
|
88
|
+
handle_error(e)
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
##
|
93
|
+
# ID is the first column you named in new()
|
94
|
+
# record should be a Hash or Octothorpe.
|
95
|
+
# Again, note that we don't care what columns you send us.
|
96
|
+
#
|
97
|
+
def update(id, record)
|
98
|
+
raise(ArgumentError, "Update requires an ID") if id.nil?
|
99
|
+
|
100
|
+
rec = @data.find{|x| x[@id_fld] == id }
|
101
|
+
raise Pod4::CantContinue, "No record found with ID '#{id}'" unless rec
|
102
|
+
|
103
|
+
rec.merge!(record.to_h)
|
104
|
+
self
|
105
|
+
rescue => e
|
106
|
+
handle_error(e)
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
##
|
111
|
+
# ID is that first column
|
112
|
+
#
|
113
|
+
def delete(id)
|
114
|
+
raise(ArgumentError, "Delete requires an ID") if id.nil?
|
115
|
+
|
116
|
+
raise Pod4::CantContinue, "'No record found with ID '#{id}'" \
|
117
|
+
if read(id).empty?
|
118
|
+
|
119
|
+
@data.delete_if {|r| r[@id_fld] == id }
|
120
|
+
self
|
121
|
+
rescue => e
|
122
|
+
handle_error(e)
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
protected
|
127
|
+
|
128
|
+
|
129
|
+
def handle_error(err, kaller=nil)
|
130
|
+
kaller ||= caller[1..-1]
|
131
|
+
|
132
|
+
Pod4.logger.error(__FILE__){ err.message }
|
133
|
+
|
134
|
+
case err
|
135
|
+
when ArgumentError, Pod4Error, Pod4::CantContinue
|
136
|
+
raise err.class, err.message, kaller
|
137
|
+
else
|
138
|
+
raise Pod4::Pod4Error, err.message, kaller
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
end
|
148
|
+
|
data/lib/pod4/param.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'octothorpe'
|
2
|
+
|
3
|
+
|
4
|
+
module Pod4
|
5
|
+
|
6
|
+
|
7
|
+
##
|
8
|
+
# This module implements the singleton pattern and is used internally to
|
9
|
+
# store parameters passed to it from outside of Pod4
|
10
|
+
#
|
11
|
+
module Param
|
12
|
+
extend self
|
13
|
+
|
14
|
+
|
15
|
+
def params; @params ||= {}; end
|
16
|
+
|
17
|
+
def set(p,v); params[p.to_s.to_sym] = v; end
|
18
|
+
|
19
|
+
def get(p); params[p.to_s.to_sym]; end
|
20
|
+
|
21
|
+
def get_all; Octothorpe.new(params.dup); end
|
22
|
+
|
23
|
+
def reset; @params = {}; end
|
24
|
+
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|