lorj 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.gitreview +4 -0
  4. data/Gemfile +25 -0
  5. data/Gemfile.lock +34 -0
  6. data/LICENSE.txt +14 -0
  7. data/README.md +652 -0
  8. data/Rakefile +24 -0
  9. data/bin/cloud_test.rb +81 -0
  10. data/example/students_1/process/Students.rb +20 -0
  11. data/example/students_1/students.rb +16 -0
  12. data/example/students_2/process/Students.rb +27 -0
  13. data/example/students_2/students.rb +36 -0
  14. data/example/students_3/controller/yaml_students.rb +94 -0
  15. data/example/students_3/controller/yaml_students_controller.rb +123 -0
  16. data/example/students_3/process/students.rb +118 -0
  17. data/example/students_3/students.rb +93 -0
  18. data/example/students_4/controller/yaml_students.rb +82 -0
  19. data/example/students_4/controller/yaml_students_controller.rb +141 -0
  20. data/example/students_4/process/students.rb +112 -0
  21. data/example/students_4/students.rb +103 -0
  22. data/example/yaml_students/students.rb +78 -0
  23. data/example/yaml_students/yaml_students.rb +115 -0
  24. data/lib/concept.md +111 -0
  25. data/lib/core/core.rb +723 -0
  26. data/lib/core/definition.rb +505 -0
  27. data/lib/core/definition_internal.rb +338 -0
  28. data/lib/core/lorj-basecontroller.rb +90 -0
  29. data/lib/core/lorj-basedefinition.rb +1079 -0
  30. data/lib/core/lorj-baseprocess.rb +231 -0
  31. data/lib/core/lorj-data.rb +567 -0
  32. data/lib/core/lorj-keypath.rb +115 -0
  33. data/lib/core_process/CloudProcess.rb +334 -0
  34. data/lib/core_process/global_process.rb +406 -0
  35. data/lib/core_process/network_process.rb +603 -0
  36. data/lib/img/.directory +4 -0
  37. data/lib/img/account_data_access.png +0 -0
  38. data/lib/img/config_data_access.png +0 -0
  39. data/lib/img/forj-lib-concept.png +0 -0
  40. data/lib/lorj/version.rb +3 -0
  41. data/lib/lorj.rb +51 -0
  42. data/lib/prc-account.rb +339 -0
  43. data/lib/prc-config.rb +1023 -0
  44. data/lib/prc-logging.rb +183 -0
  45. data/lib/prc.rb +108 -0
  46. data/lib/providers/hpcloud/Hpcloud.rb +419 -0
  47. data/lib/providers/hpcloud/compute.rb +108 -0
  48. data/lib/providers/hpcloud/network.rb +117 -0
  49. data/lib/providers/hpcloud/security_groups.rb +67 -0
  50. data/lib/providers/mock/Mock.rb +141 -0
  51. data/lib/providers/openstack/Openstack.rb +47 -0
  52. data/lib/providers/templates/compute.rb +42 -0
  53. data/lib/providers/templates/core.rb +61 -0
  54. data/lib/providers/templates/network.rb +33 -0
  55. data/lorj-spec/defaults.yaml +26 -0
  56. data/lorj.gemspec +39 -0
  57. data/spec/forj-account_spec.rb +75 -0
  58. data/spec/forj-config_spec.rb +196 -0
  59. metadata +164 -0
data/README.md ADDED
@@ -0,0 +1,652 @@
1
+ # Lorj
2
+
3
+ **Lorj** library is a process/controller framework used to build inter-operable process functions against any kind of controllers.
4
+
5
+ It has been designed to provide cloud agnostics feature to forj command line tool and FORJ maestro gardener.
6
+
7
+ This framework helps to design any kind of solution which needs to maintain a generic process logic, fully controller independant.
8
+
9
+ ## Implementations examples
10
+
11
+ ### How forj cli implemented Lorj lib
12
+
13
+ This case was implemented by forj cli to implement services on any kind of cloud solution.
14
+
15
+ forj cli needs to build a forge (collection of servers) on a cloud.
16
+ It requires to ensure that everything is in place (network properly configured if not create it, router exists, flavors available, etc.) to create the first server.
17
+
18
+ For **Lorj**, how to create the forge and ensure that everything is in place is the **process**.<br>
19
+ And then how to manipulate the cloud (get the network, create the network, create the server, etc...) is the **controller**. <br>
20
+ Usually, the controller is a wrapper to an API, which do actions, like 'create server'.
21
+
22
+ Then, at runtime, while changing the controller to aws, hpcloud, openstack, or even docker or decker, forj cli process will be still the same.
23
+ It simplifies forj cli extension, by just adding new controller to support more clouds providers.
24
+
25
+ Currently, forj cli has implemented *hpcloud* and *openstack* providers, using *fog*. Docker controller is under development.
26
+
27
+ ## Getting started
28
+
29
+ As playing by example is better than a long discussion, let's start playing with a simple example.
30
+
31
+ ### Installation
32
+
33
+ Add this line to your application's Gemfile:
34
+
35
+ ```ruby
36
+ gem 'lorj'
37
+ ```
38
+
39
+ And then execute:
40
+
41
+ $ bundle
42
+
43
+ Or install it yourself as:
44
+
45
+ $ gem install lorj
46
+
47
+
48
+ ### Write your first Lorj code
49
+
50
+ #### Student database management example context:
51
+
52
+ Imagine you have an API code which today manages students database in yaml format.<br>
53
+ We have written a small class to illustrate this API. (See examples/yaml_students/yaml_students.rb)
54
+
55
+ This api has everything to create, query, edit and delete a student in a yaml file.
56
+
57
+ Using Lorj, you want to propose multiple storage system (not only using the yaml format) to your application, by supporting several storage systems, like mysql DB.
58
+
59
+ next, we will write 3 versions, which will introduce how to deal with process and controllers:
60
+
61
+ * version 1:
62
+ Writing your first 'do nothing' process, with no controller.
63
+
64
+ * version 2:
65
+ Complete the process to have create/query/get and delete capability, with mock controller.
66
+ The mock controller is basically a controller keeping data in memory.
67
+
68
+ * version 3:
69
+ Update the version 2 to fully implement the example of an yaml_student API.
70
+
71
+ The main is `examples/yaml_students/students.rb`<BR>
72
+ The API is `examples/yaml_students/yaml_students.rb`
73
+
74
+ We have created a full example version 4 which implements some interesting way to improve your code available in `examples/students_4/`
75
+
76
+ ---
77
+ #### Writing student version 1
78
+
79
+ **NOTE**: following example is available in `examples/students_1/`
80
+
81
+ First of all, write your first main. Create a file `example.rb` with following content:
82
+
83
+ ##### File `students.rb`
84
+
85
+ ``` ruby
86
+ #!/usr/bin/env ruby
87
+
88
+ $APP_PATH = File.dirname(__FILE__)
89
+ require 'lorj'
90
+
91
+ # If you want to see what is happening in the framework, uncomment debug settings.
92
+ # PrcLib.level = Logger::DEBUG # Printed out to your console.
93
+ # PrcLib.core_level = 3 # framework debug levels.
94
+
95
+ # Initialize the framework
96
+ hProcesses = [ File.join($APP_PATH, 'process', 'students.rb')]
97
+ oStudentCore = Lorj::Core.new( nil, hProcesses)
98
+
99
+ # Ask the framework to create the object student 'Robert Redford'
100
+ oStudentCore.Create(:student, {:student_name => "Robert Redford"})
101
+ ```
102
+
103
+ ##### File `process/Students.rb`
104
+
105
+ Now, let's write our first process. We are going to create a file Students.rb under a sub-directory 'process'.
106
+
107
+ ``` ruby
108
+ # Students process
109
+ class StudentsProcess
110
+ def create_student(sObjectType, hParams)
111
+ puts "Running creation process for object '%s' = '%s'" % [sObjectType, hParams[:student_name] ]
112
+
113
+ # If you prefer to print out to the log system instead:
114
+ # PrcLib::debug("Running creation process for object '%s' = '%s'" % [sObjectType, hParams[:student_name] ])
115
+ end
116
+ end
117
+
118
+ # Declaring your data model and handlers.
119
+ class Lorj::BaseDefinition
120
+
121
+ # We need to define the student object and the handler to use while we need to create it.
122
+ define_obj(:student,
123
+ {
124
+ :create_e => :create_student # The function to call in the class Students
125
+ })
126
+
127
+ obj_needs :data, :student_name, { :for => [:create_e] }
128
+
129
+ end
130
+ ```
131
+
132
+ What did we wrote?
133
+
134
+ * We defined a *StudentsProcess* class
135
+
136
+ This is the core of your process. It describes how to handle the object requested. The data to use is available in `hParams`.
137
+
138
+ **IMPORTANT !!** There is no reference to any files or Database connection.
139
+
140
+ **NOTE**: The framework requires you to define a class name composed by the name of the process and 'Process'.
141
+ Here, it is 'Students' + **'Process'**
142
+
143
+
144
+ * We declared the data model and the process handlers with declaration in *Lorj::BaseDefinition* class.
145
+
146
+ In short, we declared `:student` object, which needs `:student_name` at creation step.
147
+
148
+ **NOTE** Implicitly, the framework consider that the object contains at least 2 data fields, :id (should be unique) and :name (string)
149
+
150
+
151
+ Currently, this model do nothing except printing out.
152
+
153
+ #####typical output
154
+
155
+ $ example/students_1/students.rb
156
+ WARNING: PrcLib.app_defaults is not set. Application defaults won't be loaded.
157
+ Running creation process for object 'student' = 'Robert Redford'
158
+ WARNING: 'create_student' has returned no data for object Lorj::Data 'student'!
159
+
160
+ There is 2 warnings.
161
+
162
+ * **PrcLib.app_defaults** represents the application name. It is used to keep your application configuration data in ~/.{PrcLib.app_defaults}/ directory. Defining this data in your main, will eliminate this warning.
163
+ * **create_student** function in your process has returned nothing. while lorj is called to create an object, it assumes to get the object data created. Lorj keep those data in a cache. In this example, **create_student** returned nil, and lorj raise a warning about that.
164
+
165
+ ---
166
+ #### Writing student version 2
167
+
168
+ **NOTE**: following example is available in `examples/students_2/`
169
+
170
+ lorj comes with a `:mock` controller. This one is really basic. It keep data in an Hash in MockController class.<br>
171
+ In this example, we add create/get/query/delete capability in the process and use the `:mock` controller to store the data.
172
+
173
+ ##### File `process/Students.rb`
174
+
175
+ Add 3 handlers query_e, get_e and delete_e like this. Add the :mapping case as well.
176
+
177
+ ``` ruby
178
+ class Lorj::BaseDefinition
179
+ define_obj(:student,
180
+ {
181
+ :create_e => :create_student, # The function to call in the class Students
182
+ :query_e => :controller_query, # We use predefined call to the controller query
183
+ :get_e => :controller_get, # We use predefined call to the controller get
184
+ :delete_e => :controller_delete # We use predefined call to the controller delete
185
+ })
186
+
187
+ # Note about mapping. This is usually done by the controller. We will see this later.
188
+ obj_needs :data, :student_name, { :for => [:create_e], :mapping => :name }
189
+
190
+ end
191
+ ```
192
+
193
+ Update the handler `create_student`:
194
+
195
+ ``` ruby
196
+ def create_student(sObjectType, hParams)
197
+ PrcLib::state ("Running creation process for object '%s' = '%s'" % [sObjectType, hParams[:student_name] ])
198
+
199
+ oObject = controler.create(sObjectType)
200
+ raise "Student '%s' not created." % hParams[:student_name] if oObject.nil?
201
+ PrcLib::info ("'%s': '%s' created with id %s" % [sObjectType, hParams[:student_name], oObject[:id]])
202
+ oObject
203
+ end
204
+ ```
205
+
206
+
207
+
208
+ ##### File `students.rb`
209
+ The update your main and add those lines. In the following, we create 3 students, while 2 are duplicated.
210
+
211
+ ``` ruby
212
+
213
+ # Want to create a duplicated student 'Robert Redford'?
214
+ oStudentCore.Create(:student)
215
+ # no problem. The key is the key in the Mock controller array.
216
+
217
+ oStudentCore.Create(:student, :student_name => "Anthony Hopkins")
218
+
219
+ # Let's create a third different student.
220
+ oStudents = oStudentCore.Query(:student, { :name => "Robert Redford" } )
221
+
222
+ puts "%s students found" % oStudents.length
223
+
224
+ oStudents.each { | oStudent |
225
+ puts "%s: %s" % [oStudent[:id], oStudent[:name]]
226
+ }
227
+
228
+ # let's check the get function, who is the ID 2?
229
+ oStudent = oStudentCore.Get(:student, 2)
230
+
231
+ puts "The student ID 2 is %s" % oStudent[:name]
232
+
233
+ ```
234
+
235
+ #####typical output:
236
+
237
+ $ example/students_2/students.rb
238
+ WARNING: PrcLib.app_defaults is not set. Application defaults won't be loaded.
239
+ 2 students found
240
+ 0: Robert Redford
241
+ 1: Robert Redford
242
+ The student ID 2 is Anthony Hopkins
243
+
244
+
245
+ Cool! But everything is in memory! We would like to write this in a file.
246
+ Writing our controller, means that the process should not be updated anymore!
247
+
248
+ Let's move to the most interesting version. Translate an API example to use lorj!
249
+
250
+ #### Writing student version 3
251
+
252
+ **NOTE**: following example is available in `examples/students_3/`
253
+
254
+ A controller is like a wrapper to an API which offer what we would like to use to save our yaml file.<br>
255
+ We already have a running API that we can use to manage students in yaml format.
256
+
257
+ This API is written in `examples/yaml_students/yaml_students.rb`. <br>
258
+ `examples/yaml_students/students.rb` is the main program calling the api and create a basic yaml file example in `/tmp/students.yaml`
259
+
260
+ You can review the main 'students.rb' to see the simple code.
261
+
262
+ In short, this code do:
263
+
264
+ * create 3 students, only if they do not exists
265
+ * remove a wrong one
266
+ * Identify list of students on a specific training
267
+ * Identify students removed.
268
+
269
+ We will do the same thing with lorj.
270
+
271
+ Using lorj means you are going to split your code in different pieces. You will need to integrate a layer between your main and the API. This layer is composed by :
272
+
273
+ * 1 generic data model
274
+ * 1 generic process handlers
275
+ * 1 controller definition - expanding the data model for our Student yaml API
276
+ * 1 controller code - wrapper to the student yaml API.
277
+
278
+ So, we are going to update following files:
279
+
280
+ * students.rb - Adapt the main to do the same as original students script using the student yaml API.
281
+ * process/students.rb - Student data model - Update the process data model.
282
+ * process/students.rb - Student process handler - Update student process handlers.
283
+ * controller/yaml_students.rb - controller definition - Extend the student data model with controller definition.
284
+ * controller/yaml_students_controller.rb - controller code - Write the student yaml API wrapper.
285
+
286
+ First of all, let me re-visit the :student data model, then the student process handlers.
287
+
288
+ We need to define more parameters for handlers, and define the data model.
289
+
290
+ ##### File `process/students.rb`
291
+ Update the class Lorj::BaseDefinition, and the data model and handlers parameters.
292
+
293
+ *The generic data model:*
294
+
295
+ ``` ruby
296
+ class Lorj::BaseDefinition
297
+ define_obj(:student,
298
+ {
299
+ :create_e => :create_student, # The function to call in the class Students
300
+ :query_e => :controller_query, # We use predefined call to the controller query
301
+ :delete_e => :controller_delete # We use predefined call to the controller delete
302
+ })
303
+
304
+ # obj_needs is used to declare parameters to pass to handlers.
305
+ # :for indicates those parameters to be passed to create_e handler only.
306
+ # Those data (or objects) will be collected and passed to the process handler as hParams.
307
+
308
+ obj_needs :data, :student_name, { :for => [:create_e] }
309
+
310
+ # By default, all data are required.
311
+ # You can set it as optional. Your process will need to deal with this optional data.
312
+ obj_needs_optional
313
+ obj_needs :data, :first_name, { :for => [:create_e] }
314
+ obj_needs :data, :last_name, { :for => [:create_e] }
315
+ obj_needs :data, :course # Note that in this model, the training is renamed as course.
316
+ # the controller will need to map it to 'training'.
317
+
318
+ # def_attribute defines the data model.
319
+ # The process will be able to access those data
320
+ # if the controller has mapped them.
321
+ # For the exercice, I have changed the name of the training field to become :course instead.
322
+ def_attribute :course
323
+ # Same thing for the student name. instead of 'name', we defined :student_name
324
+ def_attribute :student_name
325
+ def_attribute :first_name
326
+ def_attribute :last_name
327
+ def_attribute :status
328
+
329
+ undefine_attribute :name
330
+ end
331
+ ```
332
+
333
+ Then, update the process to manage student duplicates. Update function `create_student`
334
+
335
+ *The generic process handlers:*
336
+
337
+ ``` ruby
338
+ class StudentsProcess
339
+ def create_student(sObjectType, hParams)
340
+ PrcLib::state ("Running creation process for object '%s' = '%s'" % [sObjectType, hParams[:student_name] ])
341
+
342
+ # config object is a reference to runtime/config data.
343
+ oList = Query(sObjectType, {:name => hParams[:student_name]})
344
+ case oList.length
345
+ when 0
346
+ oObject = controller_create(sObjectType)
347
+ raise "Student '%s' not created." % hParams[:student_name] if oObject.nil?
348
+ PrcLib::info ("'%s': '%s' created with id %s" % [sObjectType, hParams[:student_name], oObject[:id]])
349
+ when 1
350
+ oObject = oList[0]
351
+ PrcLib::info ("'%s': '%s' loaded with id %s" % [sObjectType, hParams[:student_name], oObject[:id]])
352
+ else
353
+ oObject = oList[0]
354
+ PrcLib::warning("More than one student named '%s' is found: %s records. Selecting the first one and removing duplicates." % [hParams[:student_name], oList.length])
355
+ iCount = 0
356
+ oList[1..-1].each { | elem |
357
+ register(elem)
358
+ iCount += controller_delete(sObjectType)
359
+ }
360
+ PrcLib::info ("'%s': %s duplicated '%s' removed. First loaded with id %s" % [sObjectType, iCount, hParams[:student_name], oObject[:id]])
361
+ end
362
+ oObject
363
+ end
364
+ end
365
+ ```
366
+
367
+ Here you see that we query, check list, create if missing, or delete if duplicates found.
368
+ You can run it now, as we still uses mock controller. It should work.
369
+
370
+ ##### File `students.rb`
371
+
372
+ Now, let's update the main to be close to what we have on `examples/yaml_students/students.rb`
373
+
374
+ This is a simple basic translation of `examples/yaml_students/students.rb`
375
+
376
+ ``` ruby
377
+ #!/usr/bin/env ruby
378
+
379
+ $APP_PATH = File.dirname(__FILE__)
380
+ require 'lorj'
381
+ require 'ansi'
382
+
383
+ # If you want to see what is happening in the framework, uncomment debug settings.
384
+ # PrcLib.level = Logger::DEBUG # Printed out to your console.
385
+ # PrcLib.core_level = 3 # framework debug levels. Values between 0 to 5.
386
+
387
+ # Initialize the framework
388
+ hProcesses = [ File.join($APP_PATH, 'process', 'students.rb')]
389
+
390
+ # You can try with mock instead. uncomment the next line and comment 2 next lines.
391
+ #~ oStudentCore = Lorj::Core.new( nil, hProcesses, :mock)
392
+ oStudentCore = Lorj::Core.new( nil, hProcesses, File.join($APP_PATH, 'controller', 'yaml_students.rb'))
393
+ oStudentCore.Create(:connection, :connection_string => "/tmp/students.yaml")
394
+
395
+ puts ANSI.bold("Create 1st student:")
396
+
397
+ oStudentCore.Create(:student, {
398
+ student_name: 'Robert Redford',
399
+ first_name: 'Robert',
400
+ last_name: 'Redford',
401
+ course: 'Art Comedy'
402
+ })
403
+
404
+ puts ANSI.bold("Create 2nd student:")
405
+ oStudentCore.Create(:student, {
406
+ student_name: 'Anthony Hopkins',
407
+ first_name: 'Anthony',
408
+ last_name: 'Hopkins',
409
+ course: 'Art Drama'
410
+ })
411
+
412
+ puts ANSI.bold("Create 3rd student:")
413
+ oStudentCore.Create(:student, {
414
+ student_name: "Marilyn Monroe",
415
+ first_name: 'Marilyn',
416
+ last_name: 'Monroe',
417
+ course: 'Art Drama'
418
+ })
419
+
420
+ puts ANSI.bold("Create mistake")
421
+ oStudentCore.Create(:student, {
422
+ :student_name => "Anthony Mistake",
423
+ :first_name => 'Anthony',
424
+ :last_name => 'Mistake',
425
+ :course => 'what ever you want!!!'
426
+ })
427
+
428
+ # Because the last student was the mistake one, we can directly delete it.
429
+ # Usually, we use get instead.
430
+ puts ANSI.bold("Remove mistake")
431
+ oStudentCore.Delete(:student)
432
+
433
+ puts ANSI.bold("List of students for 'Art Drama':")
434
+ puts oStudentCore.Query(:student, { :course => "Art Drama"}).to_a
435
+
436
+ puts ANSI.bold("Deleted students:")
437
+ puts oStudentCore.Query(:student,{ :status => :removed}).to_a
438
+ ```
439
+
440
+ We have reproduced the code. Note that there is no if while creating. It is embedded in the create_student process.
441
+
442
+ ##### File `controller/yaml_students_controller.rb`
443
+
444
+ We need to write the controller part, now. As I said, it is like a wrapper. Let's have a look:
445
+
446
+ *The controller code:*
447
+
448
+ ``` ruby
449
+ # declare yaml student API to the controller
450
+ cur_file = File.expand_path(File.join(File.dirname(File.dirname(__FILE__)), "..", "yaml_students", 'yaml_students.rb'))
451
+ require cur_file
452
+
453
+ # The controller is a combination of 2 elements:
454
+ # - Controller class
455
+ # Code which will interfere with the external API.
456
+ #
457
+ # The file name must respect the name of the class. 1st letter already capitalized and letter after _ is capitalized.
458
+ # file: my_code.rb => needs to create MyCodeController class
459
+ #
460
+ # - Definition class
461
+ # This class declare any kind of mapping or additional fields to consider.
462
+ # Additionnal fields are unknow by the process. So, those fields will needs to be setup before.
463
+ #
464
+ # file name convention is identical than controller class.
465
+ # file: my_code.rb => needs to create MyCode class
466
+
467
+ class YamlStudentsController
468
+ def initialize()
469
+ @@valid_attributes = [:name, :first_name, :last_name, :id, :status, :training]
470
+ end
471
+
472
+ def create(sObjectType, hParams)
473
+ case sObjectType
474
+ when :connection
475
+ required?(hParams, :hdata, :file_name)
476
+ YamlSchool.new(hParams[:hdata, :file_name])
477
+ when :student
478
+ required?(hParams, :connection)
479
+ required?(hParams, :student_name)
480
+
481
+ # We use the hdata built by the lorj. See set_hdata in the next file.
482
+ hParams[:connection].create_student(hParams[:student_name], hParams[:hdata])
483
+ else
484
+ Error "'%s' is not a valid object for 'create'" % sObjectType
485
+ end
486
+ end
487
+
488
+ # This function return a collection which have to provide:
489
+ # functions: [], length, each
490
+ def query(sObjectType, sQuery, hParams)
491
+ case sObjectType
492
+ when :student
493
+ required?(hParams, :connection)
494
+
495
+ hParams[:connection].query_student(sQuery)
496
+ else
497
+ Error "'%s' is not a valid object for 'create'" % sObjectType
498
+ end
499
+
500
+ end
501
+
502
+ def delete(sObjectType, hParams)
503
+ case sObjectType
504
+ when :student
505
+ required?(hParams, :connection)
506
+
507
+ hParams[:connection].delete_student(hParams[sObjectType][:id])
508
+ else
509
+ Error "'%s' is not a valid object for 'create'" % sObjectType
510
+ end
511
+ end
512
+
513
+ def get_attr(oControlerObject, key)
514
+ # This controller function read the data and
515
+ # extract the information requested by the framework.
516
+ # Those data will be mapped to the process data model.
517
+ # The key is an array, to get data from a level tree.
518
+ # [data_l1, data_l2, data_l3] => should retrieve data from structure like data[ data_l2[ data_l3 ] ]
519
+ begin
520
+ attributes = oControlerObject
521
+ raise "get_attr: attribute '%s' is unknown in '%s'. Valid one are : '%s'" % [key[0], oControlerObject.class, @@valid_attributes ] unless @@valid_attributes.include?(key[0])
522
+ Lorj::rhGet(attributes, key)
523
+ rescue => e
524
+ Error "get_attr: Unable to map '%s'. %s" % [key, e.message]
525
+ end
526
+ end
527
+
528
+ def set_attr(oControlerObject, key, value)
529
+ begin
530
+ attributes = oControlerObject
531
+ raise "set_attr: attribute '%s' is unknown in '%s'. Valid one are : '%s'" % [key[0], oControlerObject.class, @@valid_attributes ] unless @@valid_attributes.include?(key[0])
532
+ Lorj::rhSet(attributes, value, key)
533
+ rescue => e
534
+ Error "set_attr: Unable to map '%s' on '%s'" % [key, sObjectType]
535
+ end
536
+ end
537
+
538
+ def update(sObjectType, oObject, hParams)
539
+ case sObjectType
540
+ when :student
541
+ required?(hParams, :connection)
542
+
543
+ hParams[:connection].update_student(oObject)
544
+ else
545
+ Error "'%s' is not a valid object for 'create'" % sObjectType
546
+ end
547
+ end
548
+
549
+ end
550
+
551
+ ```
552
+ In short, we wrap:
553
+
554
+ - create with YamlSchool.create_student
555
+ - delete with YamlSchool.delete_student
556
+ - query with YamlSchool.query_student
557
+ - update with YamlSchool.update_student
558
+
559
+ And we have defined 2 additional functions
560
+
561
+ - get_attr: to extract data from a YamlSchool Object
562
+ - set_attr: to set data to a YamlSchool Object
563
+
564
+ ##### File `controller/yaml_students.rb`
565
+
566
+ And we need to write some mapping stuff to the controller. We have to add this
567
+
568
+ *The controller definition:*
569
+
570
+ ``` ruby
571
+ class YamlStudents
572
+ # This is a new object which is known by the controller only.
573
+ # Used to open the yaml file. Generically, I named it :connection.
574
+ # But this can be any name you want. Only the controller will deal with it.
575
+ define_obj(:connection,{
576
+ :create_e => :controller_create # Nothing complex to do. So, simply call the controller create.
577
+ })
578
+
579
+ obj_needs :data, :connection_string, :mapping => :file_name
580
+ undefine_attribute :id # Do not return any predefined ID
581
+ undefine_attribute :name # Do not return any predefined NAME
582
+
583
+ # The student model have to be expanded.
584
+ define_obj(:student)
585
+ # It requires to create a connection to the data, ie opening the yaml file.
586
+ # So, before working with the :student object, the controller requires a connection
587
+ # This connection will be loaded in the memory and provided to the controller
588
+ # when needed.
589
+ obj_needs :CloudObject, :connection
590
+
591
+ # To simplify controller wrapper, we use hdata built by lorj, and passed to the API
592
+ # This hdata is a hash containing mapped data, thanks to set_hdata.
593
+ set_hdata :first_name
594
+ set_hdata :last_name
595
+ # Instead of 'course', the yaml API uses 'training'
596
+ set_hdata :course, :mapping => :training
597
+
598
+ get_attr_mapping :course, :training
599
+ # instead of 'student_name', the yaml API uses 'name'
600
+ get_attr_mapping :student_name, :name
601
+
602
+ # This controller will know how to manage a student file with those data.
603
+ # But note that the file can have a lot of more data than what the process
604
+ # usually manage. It is up to you to increase your process to manage more data.
605
+ # Then each controller may need to define mapping fields.
606
+ end
607
+ ```
608
+
609
+ That's it!
610
+
611
+ #####typical output:
612
+ $ example/students_3/students.rb
613
+ WARNING: PrcLib.app_defaults is not set. Application defaults won't be loaded.
614
+ Create 1st student:
615
+ Create 2nd student:
616
+ Create 3rd student:
617
+ Create mistake
618
+ Student created '{:id=>3, :course=>"what ever you want!!!", :student_name=>"Anthony Mistake", :first_name=>"Anthony", :last_name=>"Mistake", :status=>:active}'
619
+ Remove mistake
620
+ Wrong student to remove: 3 = Anthony Mistake
621
+ List of students for 'Art Drama':
622
+ {:id=>1, :course=>"Art Drama", :student_name=>"Anthony Hopkins", :first_name=>"Anthony", :last_name=>"Hopkins", :status=>:active}
623
+ {:id=>2, :course=>"Art Drama", :student_name=>"Marilyn Monroe", :first_name=>"Marilyn", :last_name=>"Monroe", :status=>:active}
624
+ Deleted students:
625
+ {:id=>3, :course=>"what ever you want!!!", :student_name=>"Anthony Mistake", :first_name=>"Anthony", :last_name=>"Mistake", :status=>:removed}
626
+
627
+ ## What next?
628
+
629
+ Check the code in the `examples/students_3/`. It provides a little more than is written here.
630
+
631
+ In short, it introduces the usage of Lorj::Config, before initializing Lorj::Core.
632
+
633
+ ## next features
634
+
635
+ lorj provides 2 differents configuration class.
636
+
637
+ * Lorj::Config - Basic config systems. Data are retrieved in **application defaults**, then **local config**, then **runtime**.
638
+ * Lorj::Account - Based on Lorj::Config, it introduces an **account** file, between **local config** and **runtime**.
639
+ * Logging system - Based on logger. A log file contains all data until debug. It prints to the console only data specified by PrcLib::.level
640
+ * lorj.setup - This function works with Lorj::Account. Thanks an application data definition (defaults.yaml), lorj ask the user information to build an account. Those data will be loaded and used by your process/controller flow.
641
+
642
+ For details, see API documentation.
643
+
644
+ # Contributing to Lorj
645
+
646
+ We welcome all types of contributions. Checkout our website (http://docs.forj.io/en/latest/dev/contribute.html)
647
+ to start hacking on Lorj or Forj. Also join us in our community (https://www.forj.io/community/) to help grow and foster Lorj and Forj for your development today!
648
+
649
+
650
+ #License:
651
+
652
+ Lorj lib is licensed under the Apache License, Version 2.0. See LICENSE for full license text.
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # (c) Copyright 2014 Hewlett-Packard Development Company, L.P.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require "bundler/gem_tasks"
18
+ require 'rspec/core/rake_task'
19
+
20
+ desc 'Run the specs.'
21
+ RSpec::Core::RakeTask.new do |t|
22
+ t.pattern = 'spec/*_spec.rb'
23
+ end
24
+