pod4 0.8.3 → 0.9.0

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: ece545be9a94260a395e85b9ae1333c61053d7f3
4
- data.tar.gz: 655d7a804b98519cc2cc70da7b457294bd362778
3
+ metadata.gz: 8a9606d06dd2634ff0382a7985c25e65c1dd21e0
4
+ data.tar.gz: 8a4dd824c41d8fc213dd1ebd3d29f53f2f2912d0
5
5
  SHA512:
6
- metadata.gz: 961591b60541621195119bf0c07658296cce31eafb2aa4d5c63990663b79d6e9f535946013ced7eb4f0f16826a0717f87a30dc729d3a94f30e3f8ebf57652bd1
7
- data.tar.gz: f053af3d609734f5f195bd90799524a7bd6c51cbd370577a392b04fc4970b4524866c37a7e07f55f6efd9cd9917462b7ce1e765f4cd43c9a0efd888fda965cc9
6
+ metadata.gz: c8cf85e89a6f2135e51712a6d5b06c1c233dfdc31c03852d9f4bfaf4ea3dbe7116bf1d0e81c425bdc2c91361a9811c0dee127092086c57fbf89f236e854bec34
7
+ data.tar.gz: 192f0df1a101076226c8574d53eb9dd5db353422e8f279f2e575f87e00df8c47e7a8f323cae8b226e6694a4acd5e23db33cb41074b2473e0ffe3573218b5c61d
data/.hgignore CHANGED
@@ -13,6 +13,7 @@ syntax: glob
13
13
  *.o
14
14
  *.a
15
15
  mkmf.log
16
+ .ruby-version
16
17
  .ruby-gemset
17
18
  .rbenv-gemsets
18
19
  .Project
data/.hgtags CHANGED
@@ -22,3 +22,4 @@ e41769b310f2eaab5f37d285ce9ad8658b689916 0.7.1
22
22
  ccb4a8711560725e358f7fb87c76f4787eac5ed5 0.8.0
23
23
  8dff4cc52ea1e16536ad0677d8d62f52f4201366 0.8.1
24
24
  1c06f5b53ea3f3ff235f6e54fe412ec4396cd4b1 0.8.3
25
+ 9a241db13da0e043aae02cee2ed463beca38ed9a 0.9.0
data/Gemfile CHANGED
@@ -6,14 +6,14 @@ gemspec
6
6
  group :development, :test do
7
7
 
8
8
  # for bundler, management, etc etc
9
- gem "bundler", "~> 1.13"
10
- gem "rake", "~> 12.0"
11
- gem "rspec", "~> 3.5"
9
+ gem "bundler", "~> 1.15"
10
+ gem "rake", "~> 12"
11
+ gem "rspec", "~> 3.7"
12
12
  gem 'pry'
13
13
  gem "pry-doc"
14
14
 
15
15
  # For testing
16
- gem "sequel", "~> 4.41"
16
+ gem "sequel", "~> 5.3"
17
17
  gem "nebulous_stomp", "~> 3"
18
18
 
19
19
  platforms :ruby do
data/README.md CHANGED
@@ -31,41 +31,37 @@ And here's a method that uses the model:
31
31
  Seriously now
32
32
  -------------
33
33
 
34
- Pod4 is a very simple set of classes that sits on top of some other library
35
- which gives access to data -- for example, pg, tds, or Sequel (which _is_ an
36
- ORM...) It's relatively easy to get it to talk to a new sort of data access
37
- library, and you're not limited to databases.
34
+ Pod4 is a very simple set of classes that sits on top of some other library which gives access to
35
+ data -- for example, pg, tds, or Sequel (which _is_ an ORM...) It's relatively easy to get it to
36
+ talk to a new sort of data access library, and you're not limited to databases.
38
37
 
39
- It provides a simple, common framework to talk to all these data sources, using
40
- model classes which (to my mind at least) are clean, easy to understand and
41
- maintain, using a bare minimum of DSL and vanilla Ruby inheritance.
38
+ It provides a simple, common framework to talk to all these data sources, using model classes which
39
+ (to my mind at least) are clean, easy to understand and maintain, using a bare minimum of DSL and
40
+ vanilla Ruby inheritance.
42
41
 
43
- This is the central motivation behind the project -- to provide a mechanism
44
- that allows for model classes which actually represent your data to the rest of
45
- your code in a way that you are fully in control of. Because it's your model
46
- classes, not the database, which are the canonical representation of the data.
42
+ This is the central motivation behind the project -- to provide a mechanism that allows for model
43
+ classes which actually represent your data to the rest of your code in a way that you are fully in
44
+ control of. Because it's your model classes, not the database, which are the canonical
45
+ representation of the data.
47
46
 
48
- I don't want the people who maintain my code to have to know the differences
49
- between ActiveRecord's `update` and `update_all`, or Sequel's `dataset[]` and
50
- `dataset.where()`. Pod4::Model has a dozen or so methods you need to worry
51
- about, and six of those are pretty much self-explanatory. Or, you can inherit
52
- from Pod4::BasicModel instead, and do without even that.
47
+ I don't want the people who maintain my code to have to know the differences between ActiveRecord's
48
+ `update` and `update_all`, or Sequel's `dataset[]` and `dataset.where()`. Pod4::Model has a dozen
49
+ or so methods you need to worry about, and six of those are pretty much self-explanatory. Or, you
50
+ can inherit from Pod4::BasicModel instead, and do without even that.
53
51
 
54
- I honestly don't think of it as an Object Relational Manager. I think of it as
55
- a Way To Have Nice Models.
52
+ I honestly don't think of it as an Object Relational Manager. I think of it as a Way To Have Nice Models.
56
53
 
57
- If you are looking for something with all the features of, say, ActiveRecord,
58
- then this isn't for you. I provide basic access to and maintenance of records,
59
- with validation. For anything more, you need to be willing to use a very well
60
- established existing DSL within your model code -- SQL.
54
+ If you are looking for something with all the features of, say, ActiveRecord, then this isn't for
55
+ you. I provide basic access to and maintenance of records, with validation. For anything more, you
56
+ need to be willing to use a very well established existing DSL within your model code -- SQL.
61
57
 
62
58
 
63
59
  Thanks
64
60
  ======
65
61
 
66
62
  This code was developed, by me, during working hours at [James Hall & Co.
67
- Ltd](https://www.jameshall.co.uk/). I'm incredibly greatful that they have
68
- permitted me to open-source it.
63
+ Ltd](https://www.jameshall.co.uk/). I'm incredibly greatful that they have permitted me to
64
+ open-source it.
69
65
 
70
66
 
71
67
  Installation
@@ -73,8 +69,8 @@ Installation
73
69
 
74
70
  gem install pod4
75
71
 
76
- Of course you will also need to install whatever other gems you need in order
77
- to access the data you want Pod4 to see. Currently there are interfaces for:
72
+ Of course you will also need to install whatever other gems you need in order to access the data
73
+ you want Pod4 to see. Currently there are interfaces for:
78
74
 
79
75
  * Sequel (which itself of course talks to all manner of databases)
80
76
  * Tiny_tds
@@ -87,11 +83,14 @@ to access the data you want Pod4 to see. Currently there are interfaces for:
87
83
  A Short Tutorial
88
84
  ================
89
85
 
90
- Pod4 uses my Octothorpe gem to pass information around. An Octothorpe is
91
- basically a Hash, except the keys are always symbols, and it's read only.
86
+ (Don't Worry About) Octothorpe
87
+ ------------------------------
92
88
 
93
- But you don't really need to know that here. If you mentally substitute "Hash"
94
- every time I say "Octothorpe", you'll be fine.
89
+ Pod4 uses my Octothorpe gem to pass information around. An Octothorpe is basically a Hash, except
90
+ the keys are always symbols, and it's read only.
91
+
92
+ But you don't really need to know that here. If you mentally substitute "Hash" every time I say
93
+ "Octothorpe", you'll be fine.
95
94
 
96
95
 
97
96
  Model and Interface
@@ -99,20 +98,19 @@ Model and Interface
99
98
 
100
99
  Note well that we distinguish between 'models' and 'interfaces':
101
100
 
102
- The model represents the data to your application, in the format that makes
103
- most sense to your application: that might be the same format that it is stored
104
- in on the database, or it might not. The model doesn't care about where the
105
- data comes from. Models are all subclasses of Pod4::Model (or Pod4::BasicModel,
106
- but we'll leave that alone for now).
101
+ The model represents the data to your application, in the format that makes most sense to your
102
+ application: that might be the same format that it is stored in on the database, or it might not.
103
+ The model doesn't care about where the data comes from. Models are all subclasses of Pod4::Model
104
+ (or Pod4::BasicModel, but we'll leave that alone for now).
107
105
 
108
- An interface encapsulates the connection to whatever is providing the data. It
109
- might be a wrapper for calls to the Sequel ORM, for example. Or it could be a
110
- making a series of calls to a set of Nebulous verbs. It only cares about
111
- dealing with the data source, and it is only called by the model.
106
+ An interface encapsulates the connection to whatever is providing the data. It might be a wrapper
107
+ for calls to the Sequel ORM, for example. Or it could be a making a series of calls to a set of
108
+ Nebulous verbs. It only cares about dealing with the data source, and it is only called by the
109
+ model.
112
110
 
113
- An interface is a seperate class, which is defined for each model. There are
114
- parent classes for a number of the sources you will need, but failing that,
115
- you can always create one from the ultimate parent, Pod4::Interface.
111
+ An interface is a seperate class, which is defined for each model. There are parent classes for a
112
+ number of the sources you will need, but failing that, you can always create one from the ultimate
113
+ parent, Pod4::Interface.
116
114
 
117
115
 
118
116
  Simple Model Usage
@@ -128,8 +126,8 @@ Simple Model Usage
128
126
  y.set(params)
129
127
  y.create unless y.model_status == :error
130
128
 
131
- A model is a class, each instance of which represents a single record. on that
132
- instance you can call the following for basic operation:
129
+ A model is a class, each instance of which represents a single record. on that instance you can
130
+ call the following for basic operation:
133
131
 
134
132
  * `create` -- tells the data source to store this new "record"
135
133
  * `read` -- obtains the "record" from the data source
@@ -139,25 +137,22 @@ instance you can call the following for basic operation:
139
137
  * `to_ot` -- output an Octothorpe of the object's column attributes
140
138
  * `alerts` -- return an array of Alerts (which I'll explain later)
141
139
 
142
- (Note that we say "record" not record. The data source might not be a database.
143
- Your model instance might be represented on the data source as several records,
144
- or something else entirely.)
140
+ (Note that we say "record" not record. The data source might not be a database. Your model
141
+ instance might be represented on the data source as several records, or something else entirely.)
145
142
 
146
- There is one more operation - `list`. Call this on the model class itself,
147
- and it will return an array of model instances that match the criteria you
148
- pass. What you can pass to list depends on your model class (of course); by
149
- default it also depends on the interface the model uses. But normally it should
150
- except a hash, like so:
143
+ There is one more operation - `list`. Call this on the model class itself, and it will return an
144
+ array of model instances that match the criteria you pass. What you can pass to list depends on
145
+ your model class (of course); by default it also depends on the interface the model uses. But
146
+ normally it should except a hash, like so:
151
147
 
152
148
  ExampleModel.list(:one => "a") #-> Array of ExampleModel where one = "a"
153
149
 
154
- Additionally, you can chain `or_die` onto any model method to get it to raise
155
- exceptions if something is wrong on the model. If you don't want exceptions,
156
- you can check the model's model_status attribute, or just look at the alerts.
150
+ Additionally, you can chain `or_die` onto any model method to get it to raise exceptions if
151
+ something is wrong on the model. If you don't want exceptions, you can check the model's
152
+ model_status attribute, or just look at the alerts.
157
153
 
158
- Those eight (nine) methods are _all_ the methods given by Pod4::Model that you
159
- are normally going to want to use, outside of the code actually inside your
160
- model.
154
+ Those eight (nine) methods are _all_ the methods given by Pod4::Model that you are normally going
155
+ to want to use, outside of the code actually inside your model.
161
156
 
162
157
 
163
158
  A Simple Model
@@ -180,39 +175,35 @@ Here is the model and interface definition that goes with the above example:
180
175
  attr_columns :one, :two, :three
181
176
  end
182
177
 
183
- In this example we have a model that relies on the Pg gem to talk to a
184
- table 'example'. The table has a primary key field 'id' and columns which
185
- correspond to our three attributes one, two and three. There is no validation
186
- or error control.
178
+ In this example we have a model that relies on the Pg gem to talk to a table 'example'. The table
179
+ has a primary key field 'id' and columns which correspond to our three attributes one, two and
180
+ three. There is no validation or error control.
187
181
 
188
- Note that we have to require pg_interface and pg seperately. I won't bother to
189
- show this in any more model examples.
182
+ Note that we have to require pg_interface and pg seperately. I won't bother to show this in any
183
+ more model examples.
190
184
 
191
185
  ### Interface ###
192
186
 
193
- Let's start with the interface definition. Remember, the interface class is
194
- only there to represent the data source to the model. Yours will most likely be
195
- no more complex than the one above. Since they are only accessed by the model,
196
- my preference is to define them in an internal class, but if that makes you
197
- back away slowly waving your hands placatingly, put it in another file. Pod4 is
198
- fine with that.
187
+ Let's start with the interface definition. Remember, the interface class is only there to
188
+ represent the data source to the model. Yours will most likely be no more complex than the one
189
+ above. Since they are only accessed by the model, my preference is to define them in an internal
190
+ class, but if that makes you back away slowly waving your hands placatingly, put it in another
191
+ file. Pod4 is fine with that.
199
192
 
200
- Inside your interface class you must call some DSLish methods to tell the
201
- interface how to talk to the data. What they are depends on the interface, but
202
- the ones for PgInterface are pretty common:
193
+ Inside your interface class you must call some DSLish methods to tell the interface how to talk to
194
+ the data. What they are depends on the interface, but the ones for PgInterface are pretty common:
203
195
 
204
196
  * `set_schema` -- optional -- the name of the schema to find the table in
205
197
  * `set_table` -- mandatory -- the name of the database table to use
206
198
  * `set_id_fld` -- mandatory -- the name of the column that makes the record unique
207
199
 
208
- Actually, _every_ interface defines `set_id_fld`. Instances of a model _must_ be
209
- represented by a single ID field that provides a unique identifier. Pod4 does
210
- not care what it's called or what data type it is -- if you say that's what
211
- makes it unique, that's good enough.
200
+ Actually, _every_ interface defines `set_id_fld`. Instances of a model _must_ be represented by a
201
+ single ID field that provides a unique identifier. Pod4 does not care what it's called or what data
202
+ type it is -- if you say that's what makes it unique, that's good enough.
212
203
 
213
- Internally, Interfaces talk the same basic language of list / create / read /
214
- update / delete that models do. But I'm not finding the need to subclass these
215
- much. So that's probably going to be it for your Interface definition.
204
+ Internally, Interfaces talk the same basic language of list / create / read / update / delete that
205
+ models do. But I'm not finding the need to subclass these much. So that's probably going to be it
206
+ for your Interface definition.
216
207
 
217
208
  ### Model ###
218
209
 
@@ -221,16 +212,14 @@ Models have two of their own DSLish methods:
221
212
  * `set_interface` -- here is where you instantiate your Interface class
222
213
  * `attr_columns` -- like `attr_accessor`, but letting the model know to care.
223
214
 
224
- You can see that interfaces are instantiated when the model is required.
225
- Exactly what you need to pass to the interface to instantiate it depends on the
226
- interface. SequelInterface wants the Sequel DB object (which means you have to
227
- require sequel, connect, and *then* require your models); the other interfaces
228
- only want connection hashes.
215
+ You can see that interfaces are instantiated when the model is required. Exactly what you need to
216
+ pass to the interface to instantiate it depends on the interface. SequelInterface wants the Sequel
217
+ DB object (which means you have to require sequel, connect, and *then* require your models); the
218
+ other interfaces only want connection hashes.
229
219
 
230
- Any attributes you define using `attr_columns` are treated specially by
231
- Pod4::Model. You get all the effect of the standard Ruby `attr_accessor` call,
232
- but in addition, the attribute will be passed to and from the interface, and to
233
- and from your external code, by the standard model methods.
220
+ Any attributes you define using `attr_columns` are treated specially by Pod4::Model. You get all
221
+ the effect of the standard Ruby `attr_accessor` call, but in addition, the attribute will be passed
222
+ to and from the interface, and to and from your external code, by the standard model methods.
234
223
 
235
224
  In addition to the ones above, we have:
236
225
 
@@ -250,20 +239,18 @@ We'll deal with all these below.
250
239
  Adding Validation
251
240
  -----------------
252
241
 
253
- Built into the model is an array of alerts (Pod4::Alert) which are messages
254
- that have been raised against the instance of the model class. Each alert can
255
- have a status of :error, :warning, :info or :success. If any alert has a status
256
- of :error :warning or :success then that is reflected in the model's
257
- `model_status` attribute.
242
+ Built into the model is an array of alerts (Pod4::Alert) which are messages that have been raised
243
+ against the instance of the model class. Each alert can have a status of :error, :warning, :info or
244
+ :success. If any alert has a status of :error :warning or :success then that is reflected in the
245
+ model's `model_status` attribute.
258
246
 
259
- (As to those other two possible statuses -- models are :empty when first created
247
+ (In fact, there are two other possible statuses -- models are :empty when first created
260
248
  and :deleted after a call to delete.)
261
249
 
262
- You can raise alerts yourself, and you normally do so by overriding `validate`.
263
- This method is called after a read, and before an update create or delete, so
264
- that every model instance should have a model_status reflecting its
265
- "correctness" regardless of whether it came from the data source or your
266
- application.
250
+ You can raise alerts yourself, and you normally do so by overriding `validate`. This method is
251
+ called after a read as well as when you write to the database; so that a model object should always
252
+ have a model_status reflecting its "correctness" regardless of whether it came from the data source
253
+ or your application.
267
254
 
268
255
  Here's a model with some validation:
269
256
 
@@ -294,29 +281,50 @@ Here's a model with some validation:
294
281
  (Note: as a general principal, you should always call super when overriding a
295
282
  method in Pod4 model, unless you have good reason not to.)
296
283
 
297
- If the model has a status of :error, then an update or create will fail. A
298
- delete, however, will succeed -- if you want to create validation that aborts a
299
- delete operation, you should override the `delete` method and only call super
300
- if the validation passes.
284
+ Validation is run on create, read, update and delete. If the model has a status of :error, then an
285
+ update or create will fail. A delete, however, will succeed -- if you want to create validation
286
+ that aborts a delete operation, you should override the `delete` method and only call super if the
287
+ validation passes.
301
288
 
302
- Also, because validation is not called on `set`, it's entirely possible to set
303
- a model to an invalid state and not raise any alerts against it until you go to
304
- commit to the database. If you want to change the state of the model and then
305
- validate it before that, you must call `validate` by hand.
289
+ In passing I should note that validation is _not_ run on list: every record that list returns
290
+ should be complete, but the `model_status` will be :empty because validation has not been run.
291
+ (This is partly for the sake of speed.)
306
292
 
293
+ You should be aware that validation is not called on `set`, either. Because of that, it's entirely
294
+ possible to set a model to an invalid state and not raise any alerts against it until you go to
295
+ commit to the database. If you want to change the state of the model and then validate it before
296
+ that, you must call `validate` yourself.
307
297
 
308
- Changing How a Model Represents Data
298
+ ### Conditional Validation for CRUD modes ###
299
+
300
+ If you want to write validation that only fires on some of :create, :read, :update or :delete --
301
+ for example, to stop deletion if a foreign key points to another record that exists -- then you
302
+ have two options. The recomended way to do this is to add a parameter to your `validate()` method:
303
+
304
+ def validate(vmode)
305
+ super
306
+ add_alert(:error, "foo") if vmode == :delete && bar
307
+ end
308
+
309
+ There's a little bit of magic here; when you override `validate()` you can choose to give it a
310
+ parameter or not; either way will work. The value passed to the parameter will either be :create,
311
+ :read, :update or :delete.
312
+
313
+ Your second option is to override the create/read/update/delete method, instead. Just remember to return
314
+ self, and only call super if you want the operation to go ahead.
315
+
316
+
317
+ Changine How a Model Represents Data
309
318
  ------------------------------------
310
319
 
311
- Pod4 will do the basic work for you when it comes to data types. integers,
312
- decimals, dates and datatimes should all end up as the right type in the model.
313
- (It depends on the Interface. You're going to get tired of me saying that,
314
- aren't you?) But maybe you want more than that.
320
+ Pod4 will do the basic work for you when it comes to data types. integers, decimals, dates and
321
+ datatimes should all end up as the right type in the model. (It depends on the Interface. You're
322
+ going to get tired of me saying that, aren't you?) But maybe you want more than that.
315
323
 
316
- Let's imagine you have a database table in PostreSQL with a column called cost
317
- that uses the money type. And you want it to be a `BigDecimal` in the model.
318
- Well, Pod4 won't do that for you -- for all I know someone might have a problem
319
- with my requiring BigDecimal -- but it's not hard to do yourself.
324
+ Let's imagine you have a database table in PostreSQL with a column called cost that uses the money
325
+ type. And you want it to be a `BigDecimal` in the model. Well, Pod4 won't do that for you -- for
326
+ all I know someone might have a problem with my requiring BigDecimal -- but it's not hard to do
327
+ yourself.
320
328
 
321
329
  class Product < Pod4::Model
322
330
 
@@ -340,17 +348,17 @@ with my requiring BigDecimal -- but it's not hard to do yourself.
340
348
 
341
349
  end
342
350
 
343
- `map_to_model` gets called when the model wants to write data from the interface
344
- on the model; it takes an Octothorpe from the interface as a parameter. By
345
- default it behaves as `set` does.
351
+ `map_to_model` gets called when the model wants to write data from the interface on the model; it
352
+ takes an Octothorpe from the interface as a parameter. By default it behaves as `set` does.
353
+
354
+ `map_to_interface` is the opposite: it gets called when the model wants to write data on the
355
+ interface from the model. It _returns_ an Octothorpe to the interface. By default it behaves as
356
+ `to_ot` does. (Since OTs are read only, you must modify it using merge.)
346
357
 
347
- `map_to_interface` is the opposite: it gets called when the model wants to write
348
- data on the interface from the model. It _returns_ an Octothorpe to the
349
- interface. By default it behaves as `to_ot` does. (Since OTs are read only, you
350
- must modify it using merge.)
358
+ You might also want to ensure that your data types are honoured when your application updates a
359
+ model object; in which case you will need to override `set` as well.
351
360
 
352
- By the way: sometimes I need to validate on the data before I convert it. It's
353
- fine to put a call to `add_alert` in `map_to_model`.
361
+ At some point in the future, the Pod4::TypeCasting mixin will do most of this for you.
354
362
 
355
363
 
356
364
  Relations
@@ -374,7 +382,7 @@ Pod4 does not provide relations. But, I'm not sure that it needs to. Look:
374
382
 
375
383
  class Comment < Pod4::Model
376
384
 
377
- class COmmentInterface < Pod4::PgInterface
385
+ class CommentInterface < Pod4::PgInterface
378
386
  set_table :comment
379
387
  set_id_fld :id
380
388
  end
@@ -385,23 +393,22 @@ Pod4 does not provide relations. But, I'm not sure that it needs to. Look:
385
393
  def blog_post; BlogPost.new(@post_id).read.or_die; end
386
394
  end
387
395
 
388
- So the BlogPost model has a comments method that returns an array of Comments,
389
- and the Comments model has a blog_post method that returns the BlogPost. (You
390
- would probably want to add validation to enforce relational integrity.)
396
+ So the BlogPost model has a comments method that returns an array of Comments, and the Comments
397
+ model has a blog_post method that returns the BlogPost. (You would probably want to add validation
398
+ to enforce relational integrity.)
391
399
 
392
- Is this approach inefficient? Possibly. But if you don't like it, you can
393
- always try:
400
+ Is this approach inefficient? Possibly. But if you don't like it, you can always try:
394
401
 
395
402
 
396
403
  Beyond CRUD (& List)
397
404
  --------------------
398
405
 
399
- Sooner or later you will want to do something more than Pod4::Model will give
400
- you automatically. There is a perfectly well documented, very popular DSL with
401
- lots of examples to solve this problem. It's called SQL.
406
+ Sooner or later you will want to do something more than Pod4::Model will give you automatically.
407
+ There is a perfectly well documented, very popular DSL with lots of examples to solve this problem.
408
+ It's called SQL.
402
409
 
403
- If your interface is connected to a SQL database, it should provide two more
404
- methods: `execute` and `select`.
410
+ If your interface is connected to a SQL database, it should provide two more methods: `execute` and
411
+ `select`.
405
412
 
406
413
  class BlogPost < Pod4::Model
407
414
 
@@ -436,33 +443,30 @@ methods: `execute` and `select`.
436
443
 
437
444
  end
438
445
 
439
- Neither `execute` nor `select` care about the table or ID field you passed to the
440
- interface. They only run pure SQL. The only difference between them is that
441
- select expects to return an array of results.
446
+ Neither `execute` nor `select` care about the table or ID field you passed to the interface. They
447
+ only run pure SQL. The only difference between them is that select expects to return an array of
448
+ results.
442
449
 
443
- To my way of thinking, there is absolutely nothing wrong about using SQL in a
444
- model. It will certainly need revisiting if you change database. But how often
445
- does that happen, really? And if it ever does, you are likely to need to
446
- revisit the effected models anyway...
450
+ To my way of thinking, there is absolutely nothing wrong about using SQL in a model. It will
451
+ certainly need revisiting if you change database. But how often does that happen, really? And if
452
+ it ever does, you are likely to need to revisit the effected models anyway...
447
453
 
448
454
 
449
455
  BasicModel
450
456
  ----------
451
457
 
452
- Sometimes your model needs to represent data in a way which is so radically
453
- different from the data source that the whole list, create, read, update,
454
- delete thing that Pod4::Model gives you is no use. Enter Pod4::BasicModel.
458
+ Sometimes your model needs to represent data in a way which is so radically different from the data
459
+ source that the whole list, create, read, update, delete thing that Pod4::Model gives you is no
460
+ use. Enter Pod4::BasicModel.
455
461
 
456
- A real world example: at James Hall my intranet system has a User model, where
457
- each attribute is a parameter that controls how the system behaves for that user
458
- -- email address, security settings, etc. Having one object to represent the
459
- user is the most sensible thing.
462
+ A real world example: at James Hall my intranet system has a User model, where each attribute is a
463
+ parameter that controls how the system behaves for that user -- email address, security settings,
464
+ etc. Having one object to represent the user is the most sensible thing.
460
465
 
461
- But I don't want to have to add a column to the database each time I change the
462
- intranet system and add a user parameter. The logical place to change the
463
- parameter is in the User model, not in the database, and certainly not both. So
464
- on the database, I have a settings table where the key runs: userid, setting
465
- name.
466
+ But I don't want to have to add a column to the database each time I change the intranet system and
467
+ add a user parameter. The logical place to change the parameter is in the User model, not in the
468
+ database, and certainly not both. So on the database, I have a settings table where the key runs:
469
+ userid, setting name.
466
470
 
467
471
  Pod4::BasicModel gives you:
468
472
 
@@ -470,12 +474,12 @@ Pod4::BasicModel gives you:
470
474
  * the `model_id`, `model_status` and `alerts` attributes
471
475
  * `add_alert`
472
476
 
473
- ...and nothing else. But that's enough to make a model, your way, using the
474
- methods on the interface. These are the same CRUDL methods that Pod4::Model
475
- provides -- except that the CRUD methods take a record id as a key.
477
+ ...and nothing else. But that's enough to make a model, your way, using the methods on the
478
+ interface. These are the same CRUDL methods that Pod4::Model provides -- except that the CRUD
479
+ methods take a record id as a key.
476
480
 
477
- Here's a simplified version of my User model. This one is read only, but it's
478
- hopefully enough to get the idea:
481
+ Here's a simplified version of my User model. This one is read only, but it's hopefully enough to
482
+ get the idea:
479
483
 
480
484
  class User < Pod4::BasicModel
481
485
 
@@ -87,7 +87,7 @@ module Pod4
87
87
 
88
88
 
89
89
  ##
90
- # Raise a SwingShift exception for the model if any alerts are status :error; otherwise do
90
+ # Raise a Pod4 exception for the model if any alerts are status :error; otherwise do
91
91
  # nothing.
92
92
  #
93
93
  # Note the alias of or_die for this method, which means that if you have kept to the idiom of
data/lib/pod4/errors.rb CHANGED
@@ -62,6 +62,20 @@ module Pod4
62
62
  ##
63
63
 
64
64
 
65
+ ##
66
+ # Raised by an interface if it would like Model to stop and create an Alert, but not actually
67
+ # fall over in any way.
68
+ #
69
+ class WeakError < Pod4Error
70
+
71
+ def initialize(msg=nil)
72
+ super(msg || $! && $!.message)
73
+ end
74
+
75
+ end
76
+ ##
77
+
78
+
65
79
  ##
66
80
  # Raised if validation fails (and you wanted an exception...)
67
81
  #
@@ -80,5 +94,6 @@ module Pod4
80
94
  end
81
95
 
82
96
 
97
+
83
98
  end
84
99
 
@@ -19,12 +19,15 @@ module Pod4
19
19
  # The methods below are the required ones. Interfaces will likely implement other,
20
20
  # interface-specific, ways of accessing data.
21
21
  #
22
- # In Normal use, the interface classes will in turn be subclassed as inner classes within each
22
+ # In Normal use, the interface classes may in turn be subclassed as inner classes within each
23
23
  # model, in order to customise them for the specific entity that they are drawing data from.
24
24
  #
25
25
  # Note that your Interface subclass probably returns an Octothorpe rather than a Hash, q.v..
26
26
  # (But you should be able to treat the former as if it were the latter in most cases.)
27
27
  #
28
+ # Note that if an Interface raises a Pod4::WeakError, then Pod4::Model will catch that and turn
29
+ # it into a Pod4::Alert.
30
+ #
28
31
  class Interface
29
32
  extend Metaxing
30
33