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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dc0ac6c69b4368ab5869b6ce236e1929d83fb743
4
+ data.tar.gz: 2e7a203ae10b29cc7aaac3fd743851673d494a31
5
+ SHA512:
6
+ metadata.gz: aecfa93561a918dffe716767f8fd2d60c08e64107ec5d3ddfce165af22efa9c3177e44812d58fb7ab0815febcea2a3bdb642a58167f0b1838554d70fc66ef0f9
7
+ data.tar.gz: 5be87522d0cd6726bbb2f3427c6923c19b69f0f2f35fd782511cdead8216f86e9e9ddb359fff9cb43b2c7bd38aabf2bdf18eafce19653162edf8eff64bf5a884
data/.hgignore ADDED
@@ -0,0 +1,18 @@
1
+ syntax: regexp
2
+
3
+ ^\.bundle/
4
+ ^Gemfile.lock
5
+ ^doc/
6
+ ^pkg/
7
+ ^spec/reports/
8
+ ^tmp/
9
+
10
+ syntax: glob
11
+ *.bundle
12
+ *.so
13
+ *.o
14
+ *.a
15
+ mkmf.log
16
+ .ruby-gemset
17
+ .rbenv-gemsets
18
+ .Project
data/.hgtags ADDED
@@ -0,0 +1,19 @@
1
+ 04cffd78b3e0930c939f44a989269064d7d03215 0.0.1
2
+ 287d2bb72137613beb6d823121665c7a1ced7bb1 0.0.02
3
+ 8addfcadc2235aa7af8038c704fac2c17f73116a 0.1.1
4
+ 33b88651c62b76862573eb4293b4e70db81a4b0c 0.1.2
5
+ e9204609efd7d401bdaa7f8a968f8584d70e0b48 0.1.3
6
+ 24c3a9549ca5df4d6600ff68fec425d6ad1260b6 0.2.0
7
+ 24c3a9549ca5df4d6600ff68fec425d6ad1260b6 0.2.0
8
+ c57a3e107c858f0e24d0c9ba11d411d405605b73 0.2.0
9
+ eecb1a60c825da7d4ff939dc1f170a1d37c0b32b 0.2.1
10
+ cd5e8689ef022710507836f94b3813bacba6a142 0.2.2
11
+ 06be9d910c37970a239a192676aab6324d0d6657 0.2.3
12
+ e738477c1e40988c0a6b6b38443a1981f00612a3 0.3.0
13
+ c6b6c49f3ab363771da53cb3cdbd31e284332721 0.3.1
14
+ 885291d30186092f87c62fd0225dec6fcdab2dd2 0.4.0
15
+ cea39858d97318fd8a7e32b41de7f259e367b920 0.4.1
16
+ c2743ca54c4b48c6ebe60b948d251b8d2978c90d 0.5.3
17
+ 26738ea02d5384967320ef41fc743a009faf70b8 0.6.0
18
+ dc22541876279b47dd366ddb44d262775ccdb933 0.6.1
19
+ 4a0e392be3499d9edc9cde66dd3b8d37136a0816 0.6.2
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --require spec_helper
3
+ --require doc_no_pending
4
+ -I .
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.3.0
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
data/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Andrew Jones
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9
+ of the Software, and to permit persons to whom the Software is furnished to do
10
+ so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,556 @@
1
+ Introduction
2
+ ============
3
+
4
+ Pod4 is not an ORM. No, really it isn't. Because that would be ridiculous.
5
+
6
+ ...okay, it kind of acts a _bit_ like an ORM...
7
+
8
+ Ah, well. Judge for yourself. Here's a model:
9
+
10
+ class CustomerModel < Pod4::Model
11
+
12
+ class CustomerInterface < Pod4::PgInterface
13
+ set_table :customer
14
+ set_id_fld :id
15
+ end
16
+
17
+ set_interface CustomerInterface.new(CONN_STRING)
18
+
19
+ attr_columns :cust_code, :name, :group
20
+ end
21
+
22
+ And here's a method that uses the model:
23
+
24
+ def change_customer_group(id, group)
25
+ customer = Customer.new(id).read.or_die
26
+ customer.group = group
27
+ customer.update.or_die
28
+ end
29
+
30
+
31
+ Seriously now
32
+ -------------
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.
38
+
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.
42
+
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.
47
+
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.
53
+
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.
56
+
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.
61
+
62
+
63
+ Thanks
64
+ ======
65
+
66
+ 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.
69
+
70
+
71
+ Installation
72
+ ============
73
+
74
+ gem install pod4
75
+
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:
78
+
79
+ * Sequel (which itself of course talks to all manner of databases)
80
+ * Tiny_tds
81
+ * Pg
82
+ * Nebulous (my own STOMP wrapper/protocol/what-have-you)
83
+
84
+ (But, you can add your own interfaces. It's not hard.)
85
+
86
+
87
+ A Short Tutorial
88
+ ================
89
+
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.
92
+
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.
95
+
96
+
97
+ Model and Interface
98
+ -------------------
99
+
100
+ Note well that we distinguish between 'models' and 'interfaces':
101
+
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).
107
+
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.
112
+
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.
116
+
117
+
118
+ Simple Model Usage
119
+ ------------------
120
+
121
+ # find record 14; raise error otherwise. Update and save.
122
+ x = ExampleModel.new(14).read.or_die
123
+ x.two = "new value"
124
+ x.update
125
+
126
+ # create a new record from the params hash -- unless validation fails.
127
+ y = ExampleModel.new
128
+ y.set(params)
129
+ y.create unless y.model_status == :error
130
+
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:
133
+
134
+ * `create` -- tells the data source to store this new "record"
135
+ * `read` -- obtains the "record" from the data source
136
+ * `update` -- updates the "record" on the data source
137
+ * `delete` -- deletes the "record" on the data source.
138
+ * `set` -- set the column attributes of the object with a hash or Octothorpe
139
+ * `to_ot` -- output an Octothorpe of the object's column attributes
140
+ * `alerts` -- return an array of Alerts (which I'll explain later)
141
+
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.)
145
+
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:
151
+
152
+ ExampleModel.list(:one => "a") #-> Array of ExampleModel where one = "a"
153
+
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.
157
+
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.
161
+
162
+
163
+ A Simple Model
164
+ --------------
165
+
166
+ Here is the model and interface definition that goes with the above example:
167
+
168
+ require 'pod4'
169
+ require 'pod4/pg_interface'
170
+
171
+ class ExampleModel < Pod4::Model
172
+
173
+ class ExampleInterface < Pod4::PgInterface
174
+ set_table :example
175
+ set_id_fld :id
176
+ end
177
+
178
+ set_interface ExampleInterface.new($pg_conn)
179
+ attr_columns :one, :two, :three
180
+ end
181
+
182
+ In this example we have a model that relies on the Pg gem to talk to a
183
+ table 'example'. The table has a primary key field 'id' and columns which
184
+ correspond to our three attributes one, two and three. There is no validation
185
+ or error control.
186
+
187
+ Note that we have to require pg_interface seperately. I won't bother to show
188
+ this in any more model examples.
189
+
190
+ ### Interface ###
191
+
192
+ Let's start with the interface definition. Remember, the interface class is
193
+ only there to represent the data source to the model. Yours will most likely be
194
+ no more complex than the one above. Since they are only accessed by the model,
195
+ my preference is to define them in an internal class, but if that makes you
196
+ back away slowly waving your hands placatingly, put it in another file. Pod4 is
197
+ fine with that.
198
+
199
+ Inside your interface class you must call some DSLish methods to tell the
200
+ interface how to talk to the data. What they are depends on the interface, but
201
+ the ones for PgInterface are pretty common:
202
+
203
+ * `set_schema` -- optional -- the name of the schema to find the table in
204
+ * `set_table` -- mandatory -- the name of the database table to use
205
+ * `set_id_fld` -- mandatory -- the name of the column that makes the record unique
206
+
207
+ Actually, _every_ interface defines `set_id_fld`. Instances of a model _must_ be
208
+ represented by a single ID field that provides a unique identifier. Pod4 does
209
+ not care what it's called or what data type it is -- if you say that's what
210
+ makes it unique, that's good enough.
211
+
212
+ Internally, Interfaces talk the same basic language of list / create / read /
213
+ update / delete that models do. But I'm not finding the need to subclass these
214
+ much. So that's probably going to be it for your Interface definition.
215
+
216
+ ### Model ###
217
+
218
+ Models have two of their own DSLish methods:
219
+
220
+ * `set_interface` -- here is where you instantiate your Interface class
221
+ * `attr_columns` -- like `attr_accessor`, but letting the model know to care.
222
+
223
+ You can see that interfaces are instantiated when the model is required.
224
+ Exactly what you need to pass to the interface to instantiate it depends on the
225
+ interface. SequelInterface wants the Sequel DB object (which means you have to
226
+ require sequel, connect, and *then* require your models); the other interfaces
227
+ only want connection hashes.
228
+
229
+ Any attributes you define using `attr_columns` are treated specially by
230
+ Pod4::Model. You get all the effect of the standard Ruby `attr_accessor` call,
231
+ but in addition, the attribute will be passed to and from the interface, and to
232
+ and from your external code, by the standard model methods.
233
+
234
+ In addition to the ones above, we have:
235
+
236
+ * `validate` -- override this to provide validation
237
+ * `map_to_model` -- controls how the interface sets attributes on the model
238
+ * `map_to_interface` -- controls how the model sends data to the interface
239
+ * `add_alert` -- adds an alert to the model
240
+
241
+ A model also has some built-in attributes of its own:
242
+
243
+ * `model_id` -- this is the value of the ID column you set in the interface.
244
+ * `model_status` -- one of :error :warning :okay :deleted :empty
245
+
246
+ We'll deal with all these below.
247
+
248
+
249
+ Adding Validation
250
+ -----------------
251
+
252
+ Built into the model is an array of alerts (Pod4::Alert) which are messages
253
+ that have been raised against the instance of the model class. Each alert can
254
+ have a status of :error, :warning, :info or :success. If any alert has a status
255
+ of :error :warning or :success then that is reflected in the model's
256
+ `model_status` attribute.
257
+
258
+ (As to those other two possible statuses -- models are :empty when first created
259
+ and :deleted after a call to delete.)
260
+
261
+ You can raise alerts yourself, and you normally do so by overriding `validate`.
262
+ This method is called after a read, and before an update create or delete, so
263
+ that every model instance should have a model_status reflecting its
264
+ "correctness" regardless of whether it came from the data source or your
265
+ application.
266
+
267
+ Here's a model with some validation:
268
+
269
+ class Customer < Pod4::Model
270
+
271
+ class CustomerInterface < Pod4::PgInterface
272
+ set_schema :pod4example
273
+ set_table :customer
274
+ set_id_fld :id
275
+ end
276
+
277
+ set_interface CustomerInterface.new($pg_conn)
278
+ attr_columns :cust_code, :name, :group
279
+
280
+ def validate
281
+ super
282
+
283
+ add_alert(:error, :name, "Name cannot be empty") \
284
+ unless @name && @name =~ \^\s*$\
285
+
286
+ add_alert(:error, :cust_code, "invalid customer code") \
287
+ unless @cust_code && @cust_code.length == 6
288
+
289
+ end
290
+
291
+ end
292
+
293
+ (Note: as a general principal, you should always call super when overriding a
294
+ method in Pod4 model, unless you have good reason not to.)
295
+
296
+ If the model has a status of :error, then an update or create will fail. A
297
+ delete, however, will succeed -- if you want to create validation that aborts a
298
+ delete operation, you should override the `delete` method and only call super
299
+ if the validation passes.
300
+
301
+ Also, because validation is not called on `set`, it's entirely possible to set
302
+ a model to an invalid state and not raise any alerts against it until you go to
303
+ commit to the database. If you want to change the state of the model and then
304
+ validate it before that, you must call `validate` by hand.
305
+
306
+
307
+ Changing How a Model Represents Data
308
+ ------------------------------------
309
+
310
+ Pod4 will do the basic work for you when it comes to data types. integers,
311
+ decimals, dates and datatimes should all end up as the right type in the model.
312
+ (It depends on the Interface. You're going to get tired of me saying that,
313
+ aren't you?) But maybe you want more than that.
314
+
315
+ Let's imagine you have a database table in PostreSQL with a column called cost
316
+ that uses the money type. And you want it to be a `BigDecimal` in the model.
317
+ Well, Pod4 won't do that for you -- for all I know someone might have a problem
318
+ with my requiring BigDecimal -- but it's not hard to do yourself.
319
+
320
+ class Product < Pod4::Model
321
+
322
+ class ProductInterface < Pod4::PgInterface
323
+ set_schema :pod4example
324
+ set_table :product
325
+ set_id_fld :product_id
326
+ end
327
+
328
+ set_interface ProductInterface.new($pg_conn)
329
+ attr_columns :description, :cost
330
+
331
+ def map_to_model(ot)
332
+ super
333
+ @cost = Bigdecimal.new(@cost)
334
+ end
335
+
336
+ def map_to_interface
337
+ super.merge(cost: @cost.to_f)
338
+ end
339
+
340
+ end
341
+
342
+ `map_to_model` gets called when the model wants to write data from the interface
343
+ on the model; it takes an Octothorpe from the interface as a parameter. By
344
+ default it behaves as `set` does.
345
+
346
+ `map_to_interface` is the opposite: it gets called when the model wants to write
347
+ data on the interface from the model. It _returns_ an Octothorpe to the
348
+ interface. By default it behaves as `to_ot` does. (Since OTs are read only, you
349
+ must modify it using merge.)
350
+
351
+ By the way: sometimes I need to validate on the data before I convert it. It's
352
+ fine to put a call to `add_alert` in `map_to_model`.
353
+
354
+
355
+ Relations
356
+ ---------
357
+
358
+ Pod4 does not provide relations. But, I'm not sure that it needs to. Look:
359
+
360
+ class BlogPost < Pod4::Model
361
+
362
+ class BlogPostInterface < Pod4::PgInterface
363
+ set_table :blogpost
364
+ set_id_fld :id
365
+ end
366
+
367
+ set_interface BlogPostInterface.new($conn)
368
+ attr_columns :text
369
+
370
+ def comments; Comment.list(post: @id); end
371
+ end
372
+
373
+
374
+ class Comment < Pod4::Model
375
+
376
+ class COmmentInterface < Pod4::PgInterface
377
+ set_table :comment
378
+ set_id_fld :id
379
+ end
380
+
381
+ set_interface CommentInterface.new($conn)
382
+ attr_columns :post_id, :text
383
+
384
+ def blog_post; BlogPost.new(@post_id).read.or_die; end
385
+ end
386
+
387
+ So the BlogPost model has a comments method that returns an array of Comments,
388
+ and the Comments model has a blog_post method that returns the BlogPost. (You
389
+ would probably want to add validation to enforce relational integrity.)
390
+
391
+ Is this approach inefficient? Possibly. But if you don't like it, you can
392
+ always try:
393
+
394
+
395
+ Beyond CRUD (& List)
396
+ --------------------
397
+
398
+ Sooner or later you will want to do something more than Pod4::Model will give
399
+ you automatically. There is a perfectly well documented, very popular DSL with
400
+ lots of examples to solve this problem. It's called SQL.
401
+
402
+ If your interface is connected to a SQL database, it should provide two more
403
+ methods: `execute` and `select`.
404
+
405
+ class BlogPost < Pod4::Model
406
+
407
+ class BlogPostInterface < Pod4::PgInterface
408
+ set_table :blogpost
409
+ set_id_fld :id
410
+ end
411
+
412
+ set_interface BlogPostInterface.new($conn)
413
+ attr_columns :text
414
+
415
+
416
+ ##
417
+ # return an array of hashes where each comment has the post joined to it
418
+ #
419
+ def post_and_comments
420
+ interface.select( %Q|select *
421
+ from blogpost b
422
+ join comments c on(c.post_id = b.id);| )
423
+
424
+ end
425
+
426
+
427
+ ##
428
+ # delete all comments on this post
429
+ #
430
+ def delete_comments
431
+ interface.execute(
432
+ %Q|delete from comments where post_id = #{@model_id};| )
433
+
434
+ end
435
+
436
+ end
437
+
438
+ Neither `execute` nor `select` care about the table or ID field you passed to the
439
+ interface. They only run pure SQL. The only difference between them is that
440
+ select expects to return an array of results.
441
+
442
+ To my way of thinking, there is absolutely nothing wrong about using SQL in a
443
+ model. It will certainly need revisiting if you change database. But how often
444
+ does that happen, really? And if it ever does, you are likely to need to
445
+ revisit the effected models anyway...
446
+
447
+
448
+ BasicModel
449
+ ----------
450
+
451
+ Sometimes your model needs to represent data in a way which is so radically
452
+ different from the data source that the whole list, create, read, update,
453
+ delete thing that Pod4::Model gives you is no use. Enter Pod4::BasicModel.
454
+
455
+ A real world example: at James Hall my intranet system has a User model, where
456
+ each attribute is a parameter that controls how the system behaves for that user
457
+ -- email address, security settings, etc. Having one object to represent the
458
+ user is the most sensible thing.
459
+
460
+ But I don't want to have to add a column to the database each time I change the
461
+ intranet system and add a user parameter. The logical place to change the
462
+ parameter is in the User model, not in the database, and certainly not both. So
463
+ on the database, I have a settings table where the key runs: userid, setting
464
+ name.
465
+
466
+ Pod4::BasicModel gives you:
467
+
468
+ * `set_interface`
469
+ * the `model_id`, `model_status` and `alerts` attributes
470
+ * `add_alert`
471
+
472
+ ...and nothing else. But that's enough to make a model, your way, using the
473
+ methods on the interface. These are the same CRUDL methods that Pod4::Model
474
+ provides -- except that the CRUD methods take a record id as a key.
475
+
476
+ Here's a simplified version of my User model. This one is read only, but it's
477
+ hopefully enough to get the idea:
478
+
479
+ class User < Pod4::BasicModel
480
+
481
+ class UserInterface < ::Pod4::SequelInterface
482
+ set_table :settings
483
+ set_id_fld :id
484
+ end
485
+
486
+
487
+ # Here we set what settings always exist for a user
488
+ Setting = Struct.new(:setName, :default)
489
+
490
+ DefaultSettings = [ Setting.new( :depot, nil ),
491
+ Setting.new( :store, nil ),
492
+ Setting.new( :menu, nil ),
493
+ Setting.new( :roles, '' ),
494
+ Setting.new( :name, '' ),
495
+ Setting.new( :nick, '' ),
496
+ Setting.new( :mail, nil ) ]
497
+
498
+ set_interface UserInterface.new($db)
499
+ attr_reader :userid, :depot, :store, :menu, :roles, :name, :nick, :mail
500
+
501
+
502
+ class << self
503
+
504
+ def keys; DefaultSettings.map{|x| x.setName }; end
505
+
506
+ def list
507
+ array = interface.select(%Q|select distinct userid from settings;|)
508
+ array.map {|r| self.new( r[:userid] ).read }
509
+ end
510
+
511
+ end
512
+ ##
513
+
514
+
515
+ def initialize(userid=nil)
516
+ super(userid)
517
+
518
+ self.class.keys.each do |key|
519
+ instance_variable_set( "@#{key}".to_sym, nil )
520
+ end
521
+ end
522
+
523
+
524
+ def read
525
+ lst = interface.list(userid: @model_id)
526
+
527
+ data = lst.each_with_object({}) do |ot,h|
528
+ h[ot.>>.setname] = ot.>>.setvalue
529
+ end
530
+
531
+ @userid = @model_id
532
+ set_merge( Octothorpe.new(data) )
533
+ validate; @model_status = :okay unless @model_status != :empty
534
+
535
+ self
536
+ end
537
+
538
+
539
+ def to_ot
540
+ hash = self.class.keys.each_with_object({}) do |k,m|
541
+ m[k] = instance_variable_get("@#{k}".to_sym)
542
+ end
543
+
544
+ Octothorpe.new(hash)
545
+ end
546
+
547
+
548
+ def set_merge(hash)
549
+ self.class.keys.each do |key|
550
+ value = hash[key]
551
+ instance_variable_set( "@#{key}".to_sym, value ) if value
552
+ end
553
+ end
554
+
555
+ end
556
+
data/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ require 'rdoc/task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ namespace :rdoc do
8
+ RDoc::Task.new do |rdoc|
9
+ rdoc.main = "README.md"
10
+ rdoc.rdoc_files.include("*.md", "lib/*", "md/*")
11
+ rdoc.rdoc_dir = "doc"
12
+ end
13
+
14
+ desc "Push doc to HARS"
15
+ task :hars do
16
+ sh "rsync -aP --delete doc/ /home/hars/hars/public/pod4"
17
+ end
18
+
19
+ end
20
+
21
+ desc "Start Guard"
22
+ task :guard do
23
+ sh "bundle exec guard"
24
+ end
25
+
26
+ desc "Update vim tag data"
27
+ task :retag do
28
+ sh "ripper-tags -R"
29
+ end
30
+