lorj 1.0.1 → 1.0.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.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/README.md +39 -579
  4. data/Rakefile +7 -0
  5. data/example/students_1/student_v1.md +115 -0
  6. data/example/students_1/students.rb +8 -2
  7. data/example/students_2/process/students.rb +5 -5
  8. data/example/students_2/student_v2.md +90 -0
  9. data/example/students_2/students.rb +6 -6
  10. data/example/students_3/controller/yaml_students.rb +23 -73
  11. data/example/students_3/controller/yaml_students_code.rb +106 -0
  12. data/example/students_3/controller/yaml_students_def.rb +69 -0
  13. data/example/students_3/process/students.rb +23 -157
  14. data/example/students_3/student_v3.md +283 -0
  15. data/example/students_3/students.rb +26 -83
  16. data/example/students_4/controller/yaml_students.rb +51 -0
  17. data/example/students_4/controller/yaml_students_code.rb +109 -0
  18. data/example/students_4/controller/yaml_students_def.rb +72 -0
  19. data/example/students_4/process/students/code/students.rb +103 -0
  20. data/example/students_4/process/students/definition/students.rb +60 -0
  21. data/example/students_4/process/students.rb +29 -0
  22. data/example/students_4/student_v4.md +191 -0
  23. data/example/students_4/students.rb +65 -0
  24. data/example/students_5/controller/yaml_students.rb +106 -0
  25. data/example/{students_3 → students_5}/controller/yaml_students_controller.rb +5 -3
  26. data/example/students_5/process/students.rb +182 -0
  27. data/example/students_5/student_v5.md +382 -0
  28. data/example/students_5/students.rb +119 -0
  29. data/example/yaml_students/students.rb +1 -1
  30. data/example/yaml_students/yaml_students.rb +102 -23
  31. data/lib/concept.md +3 -3
  32. data/lib/core/core.rb +15 -15
  33. data/lib/core/core_controller.rb +49 -24
  34. data/lib/core/core_internal.rb +2 -2
  35. data/lib/core/core_model.rb +13 -7
  36. data/lib/core/core_object_data.rb +18 -18
  37. data/lib/core/core_object_params.rb +75 -34
  38. data/lib/core/core_process.rb +104 -59
  39. data/lib/core/core_process_setup.rb +11 -11
  40. data/lib/core/core_setup_ask.rb +24 -14
  41. data/lib/core/core_setup_encrypt.rb +17 -15
  42. data/lib/core/core_setup_init.rb +19 -15
  43. data/lib/core/core_setup_list.rb +12 -12
  44. data/lib/core/definition.rb +20 -20
  45. data/lib/core/definition_internal.rb +20 -10
  46. data/lib/core/lorj_basecontroller.rb +8 -8
  47. data/lib/core/lorj_basedefinition.rb +47 -126
  48. data/lib/core/lorj_baseprocess.rb +81 -57
  49. data/lib/core/lorj_data.rb +28 -27
  50. data/lib/core/lorj_keypath.rb +1 -1
  51. data/lib/core_process/cloud/process/flavor.rb +3 -2
  52. data/lib/core_process/cloud/process/keypairs.rb +5 -4
  53. data/lib/core_process/cloud/process/network.rb +4 -3
  54. data/lib/core_process/cloud/process/public_ip.rb +3 -2
  55. data/lib/core_process/cloud/process/rules.rb +7 -6
  56. data/lib/core_process/cloud/process/security_groups.rb +1 -1
  57. data/lib/core_process/cloud/process/server.rb +1 -1
  58. data/lib/core_process/cloud/process/server_log.rb +1 -1
  59. data/lib/core_process/cloud/process/subnetwork.rb +4 -1
  60. data/lib/core_process/cloud_process.rb +1 -1
  61. data/lib/logging.rb +41 -48
  62. data/lib/lorj/version.rb +1 -1
  63. data/lib/lorj.rb +7 -0
  64. data/lib/lorj_account.rb +3 -3
  65. data/lib/lorj_config.rb +1 -1
  66. data/lib/lorj_defaults.rb +222 -26
  67. data/lib/overview.md +120 -0
  68. data/lib/prc.rb +97 -24
  69. data/lib/prc_core_config.rb +134 -52
  70. data/lib/providers/hpcloud/compute.rb +3 -3
  71. data/lib/providers/hpcloud/hpcloud.rb +14 -14
  72. data/lib/providers/hpcloud/network.rb +4 -4
  73. data/lib/providers/hpcloud/security_groups.rb +1 -1
  74. data/lib/providers/mock/mock.rb +3 -3
  75. data/lib/providers/openstack/openstack.rb +12 -12
  76. data/lib/providers/templates/compute.rb +6 -6
  77. data/lib/rh.rb +7 -5
  78. data/spec/04_prc_core_config_spec.rb +52 -0
  79. data/spec/11_lorj_config_spec.rb +1 -1
  80. metadata +21 -3
@@ -0,0 +1,106 @@
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
+ # when you declare this controller with a file name, lorj expect this file
18
+ # to contains the controller code and the controller definition.
19
+ # The code have to be declared in a class which is named as follow from the file
20
+ # name:
21
+ # 1st letter is capitalized
22
+ # A '_' followed by a letterif replaced by the capicatl letter.
23
+ # Ex: my_code.rb => assume to declare MyCode class
24
+ #
25
+ # The controller code class is built from the source file name as explained
26
+ # below + 'Controller'
27
+ # Ex: my_code.rb => assume to use MyCodeController for controller handlers and
28
+ # functions.
29
+ #
30
+ # The controller definition class is build from the file name only.
31
+ # Ex: my_code.rb => assume to use MyCode for controller definition.
32
+
33
+ # This class describes how to process some actions, and will do everything prior
34
+ # this task to make it to work.
35
+
36
+ # declare yaml student API to the controller
37
+ cur_path = File.expand_path(File.dirname(__FILE__))
38
+ api_file = File.join(cur_path, '..', '..', 'yaml_students', 'yaml_students.rb')
39
+
40
+ require api_file
41
+
42
+ # The controller is a combination of 2 elements:
43
+ # - Controller class
44
+ # Code which will interfere with the external API.
45
+ #
46
+ # - Definition class
47
+ # This class declare any kind of mapping or additional attributes to consider.
48
+ controller_file = File.join(cur_path, 'yaml_students_controller.rb')
49
+ require controller_file # Load controller mapping
50
+
51
+ # Declare
52
+ # - additional objects and their specific process (:connection using basic
53
+ # predefined :controller_create process)
54
+ # - data_mapping :
55
+ # :connection_string => :file_name
56
+ # :course => :training
57
+ #
58
+ # If some data has been added by the controller, the main and process,
59
+ # won't take care and the framework will fails.
60
+ # To eliminate this errors, there is 2 cases:
61
+ # - detect this change in the process or the main.
62
+ # - set it up, using lorj setup function, if the data is declared askable by
63
+ # the controller.
64
+ # The controller can define how the setup have to ask values, and even can get
65
+ # data from itself.
66
+ class YamlStudents
67
+ # This is a new object which is known by the controller only.
68
+ # Used to open the yaml file. Generically, I named it :connection.
69
+ # But this can be any name you want. Only the controller will deal with it.
70
+ define_obj(:connection,
71
+ # Nothing complex to do. So, simply call the controller create.
72
+ :create_e => :controller_create
73
+ )
74
+
75
+ obj_needs :data, :connection_string, :mapping => :file_name
76
+ undefine_attribute :id # Do not return any predefined ID
77
+ undefine_attribute :name # Do not return any predefined NAME
78
+
79
+ # The student model have to be expanded.
80
+ define_obj(:student)
81
+ # It requires to create a connection to the data, ie opening the yaml file.
82
+ # So, before working with the :student object, the controller requires a
83
+ # connection
84
+ # This connection will be loaded in the memory and provided to the controller
85
+ # when needed.
86
+ # obj_needs :CloudObject update the :student object to requires a connection
87
+ # before.
88
+ obj_needs :CloudObject, :connection
89
+
90
+ # To simplify controller wrapper, we use hdata built by lorj, and passed to
91
+ # the API
92
+ # This hdata is a hash containing mapped data, thanks to def_hdata.
93
+ def_hdata :first_name
94
+ def_hdata :last_name
95
+ # Instead of 'course', the yaml API uses 'training'
96
+ def_hdata :course, :mapping => :training
97
+
98
+ def_attr_mapping :course, :training
99
+ # instead of 'student_name', the yaml API uses 'name'
100
+ def_attr_mapping :student_name, :name
101
+
102
+ # This controller will know how to manage a student file with those data.
103
+ # But note that the file can have a lot of more data than what the process
104
+ # usually manage. It is up to you to increase your process to manage more data
105
+ # Then each controller may need to define mapping fields.
106
+ end
@@ -21,9 +21,9 @@
21
21
 
22
22
  # declare yaml student API to the controller
23
23
  yaml_students_file = File.expand_path(
24
- File.join(
25
- File.dirname(__FILE__),
26
- '..', '..', 'yaml_students', 'yaml_students.rb'))
24
+ File.join(
25
+ File.dirname(__FILE__),
26
+ '..', '..', 'yaml_students', 'yaml_students.rb'))
27
27
  require yaml_students_file
28
28
 
29
29
  # The controller is a combination of 2 elements:
@@ -47,6 +47,8 @@ class YamlStudentsController
47
47
  def create(sObjectType, hParams)
48
48
  case sObjectType
49
49
  when :connection
50
+ byebug if ENV['BYEBUG'] # rubocop: disable Debugger
51
+
50
52
  required?(hParams, :hdata, :file_name)
51
53
  YamlSchool.new(hParams[:hdata, :file_name])
52
54
  when :student
@@ -0,0 +1,182 @@
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
+ # Students process - Define specific handlers
18
+ class StudentsProcess
19
+ # create_student process handler to get a student.
20
+ #
21
+ # * If not found, create it.
22
+ # * If multiple found, remove duplicates
23
+ # * otherwise return the one found.
24
+ # rubocop:disable Metrics/MethodLength
25
+ def create_student(sObjectType, hParams)
26
+ PrcLib.state(format("Running creation process for object '%s' = '%s'",
27
+ sObjectType, hParams[:student_name]))
28
+
29
+ list = process_query(sObjectType, :student_name => hParams[:student_name])
30
+ case list.length
31
+ when 0
32
+ create_new_student(hParams[:student_name])
33
+ when 1
34
+ found_one_student(list[0], hParams[:student_name])
35
+ else
36
+ found_multiple_students(list, hParams[:student_name])
37
+ end
38
+ end
39
+ # rubocop:enable Metrics/MethodLength
40
+
41
+ private
42
+
43
+ # Create a single new student
44
+ def create_new_student(student_name)
45
+ object = controller_create(:student)
46
+ fail format("Student '%s' not created.", student_name) if object.nil?
47
+
48
+ PrcLib.info(format("'student': '%s' created with id %s",
49
+ student_name,
50
+ object[:id]))
51
+ object
52
+ end
53
+
54
+ # Identified 1 student
55
+ def found_one_student(object, student_name)
56
+ PrcLib.info(format("'student': '%s' loaded with id %s",
57
+ student_name, object[:id]))
58
+ object
59
+ end
60
+
61
+ # Identified multiple identical students
62
+ # It will remove duplicated.
63
+ def found_multiple_students(list, student_name)
64
+ object = list[0]
65
+ PrcLib.warning(format("More than one student named '%s' is found: %s "\
66
+ 'records. Selecting the first one and removing '\
67
+ 'duplicates.',
68
+ student_name, list.length))
69
+ remove_multiple_students(list[1..-1], student_name)
70
+ object
71
+ end
72
+
73
+ # Remove list of identical students
74
+ def remove_multiple_students(list, student_name)
75
+ return false unless list.is_a?(Array)
76
+ return false if list.length == 0
77
+
78
+ count = 0
79
+ list.each { |elem| count += remove_student_object(elem) }
80
+ PrcLib.info(format("'student': %s duplicated '%s' removed. "\
81
+ 'First loaded with id %s',
82
+ count, student_name, object[:id]))
83
+ end
84
+
85
+ def remove_student_object(object)
86
+ register(object)
87
+ controller_delete(:student)
88
+ end
89
+
90
+ # The following handler is inactive.
91
+ # It provides a simple print-out code.
92
+ # If you want to activate it:
93
+ # * uncomment query_student function
94
+ # * update the :student data model
95
+ # on query_e, replace controller_query by query_student
96
+
97
+ # def query_student(sObjectType, sQuery, hParams)
98
+ # PrcLib::state (format("Running query process for object '%s' "\
99
+ # "with query '%s'",
100
+ # sObjectType,
101
+ # sQuery))
102
+ #
103
+ # objects = controller_query(sObjectType, sQuery)
104
+ # raise "Query error." if objects.nil?
105
+ #
106
+ # PrcLib::info (format("'%s': Queried. %s records found.",
107
+ # sObjectType,
108
+ # objects.length))
109
+ # objects
110
+ # end
111
+
112
+ # This handler is inactive.
113
+ # It provides a simple print-out code.
114
+ # If you want to activate it:
115
+ # * uncomment get_student function
116
+ # * update the :student data model
117
+ # on get_e, replace controller_get by get_student
118
+
119
+ # def delete_student(sObjectType, hParams)
120
+ # controller_delete(:student)
121
+ # PrcLib::info (format("'%s:%s' student removed",
122
+ # hParams[:student, :id],
123
+ # hParams[:student, :name]))
124
+ # end
125
+ end
126
+
127
+ module Lorj
128
+ # Declaring your data model and handlers.
129
+ # Process Handlers functions have to be declared before, as lorj check their
130
+ # existence during data model definition.
131
+ class BaseDefinition
132
+ # We need to define the student object data model and process handlers to
133
+ # use.
134
+ # Process handlers must manipulate data defined here.
135
+ #
136
+ # The controller can redefine object for it needs, but should NEVER impact
137
+ # the main process.
138
+ # The controller can add specific process to deal with internal controller
139
+ # objects.
140
+ # But this should never influence the original process model.
141
+
142
+ # Use define_obj, to declare the new object managed by lorj with process
143
+ # handlers.
144
+
145
+ define_obj(:student,
146
+ # The function to call in the class Students
147
+ :create_e => :create_student,
148
+ # We use predefined call to the controller query
149
+ :query_e => :controller_query,
150
+ # We use predefined call to the controller delete
151
+ :delete_e => :controller_delete
152
+ )
153
+
154
+ # obj_needs is used to declare parameters to pass to handlers.
155
+ # :for indicates those parameters to be passed to create_e handler only.
156
+ # Those data (or objects) will be collected and passed to the process
157
+ # handler as hParams.
158
+
159
+ obj_needs :data, :student_name, :for => [:create_e]
160
+
161
+ # By default, all data are required.
162
+ # You can set it as optional. Your process will need to deal with this
163
+ # optional data.
164
+ obj_needs_optional
165
+ obj_needs :data, :first_name, :for => [:create_e]
166
+ obj_needs :data, :last_name, :for => [:create_e]
167
+ obj_needs :data, :course
168
+ # Note that in this model, the training is renamed as course.
169
+
170
+ # the controller will need to map it to 'training'.
171
+
172
+ # def_attribute defines the data model.
173
+ # The process will be able to access those data
174
+ def_attribute :course
175
+ def_attribute :student_name
176
+ def_attribute :first_name
177
+ def_attribute :last_name
178
+ def_attribute :status
179
+
180
+ undefine_attribute :name
181
+ end
182
+ end
@@ -0,0 +1,382 @@
1
+ # Writing student version 5
2
+
3
+ **NOTE**: following example is available in `examples/students_5/`
4
+
5
+ In this last example, we are fully implementing the yaml_student example which
6
+ is demonstrated in `examples/yaml_students/students.rb`.
7
+ this script is the main program calling the api and create a basic yaml file example in `/tmp/students.yaml`
8
+
9
+ So, we are going to update this main to use lorj instead and reproduce the same
10
+ functionnality.
11
+
12
+ You can review the script 'students.rb' to see the simple code.
13
+
14
+ In short, this code do:
15
+
16
+ * create 3 students, only if they do not exists
17
+ * remove a wrong one
18
+ * Identify list of students on a specific training
19
+ * Identify students removed.
20
+
21
+ We will do the same thing with lorj.
22
+
23
+ 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 :
24
+
25
+ * 1 generic data model
26
+ * 1 generic process handlers
27
+ * 1 controller definition - expanding the data model for our Student yaml API
28
+ * 1 controller code - wrapper to the student yaml API.
29
+
30
+ So, we are going to update following files:
31
+
32
+ * students.rb - Adapt the main to do the same as original students script using the student yaml API.
33
+ * process/students.rb - Student data model - Update the process data model.
34
+ * process/students.rb - Student process handler - Update student process handlers.
35
+ * controller/yaml_students.rb - controller definition - Extend the student data model with controller definition.
36
+ * controller/yaml_students_controller.rb - controller code - Write the student yaml API wrapper.
37
+
38
+ First of all, let me re-visit the :student data model, then the student process handlers.
39
+
40
+ We need to define more parameters for handlers, and define the data model.
41
+
42
+ ##### File `process/students.rb`
43
+ Update the class Lorj::BaseDefinition, and the data model and handlers parameters.
44
+
45
+ *The generic data model:*
46
+
47
+ ``` ruby
48
+ class Lorj::BaseDefinition
49
+ define_obj(:student,
50
+ {
51
+ :create_e => :create_student, # The function to call in the class Students
52
+ :query_e => :controller_query, # We use predefined call to the controller query
53
+ :delete_e => :controller_delete # We use predefined call to the controller delete
54
+ })
55
+
56
+ # obj_needs is used to declare parameters to pass to handlers.
57
+ # :for indicates those parameters to be passed to create_e handler only.
58
+ # Those data (or objects) will be collected and passed to the process handler as hParams.
59
+
60
+ obj_needs :data, :student_name, { :for => [:create_e] }
61
+
62
+ # By default, all data are required.
63
+ # You can set it as optional. Your process will need to deal with this optional data.
64
+ obj_needs_optional
65
+ obj_needs :data, :first_name, { :for => [:create_e] }
66
+ obj_needs :data, :last_name, { :for => [:create_e] }
67
+ obj_needs :data, :course # Note that in this model, the training is renamed as course.
68
+ # the controller will need to map it to 'training'.
69
+
70
+ # def_attribute defines the data model.
71
+ # The process will be able to access those data
72
+ # if the controller has mapped them.
73
+ # For the exercice, I have changed the name of the training field to become :course instead.
74
+ def_attribute :course
75
+ # Same thing for the student name. instead of 'name', we defined :student_name
76
+ def_attribute :student_name
77
+ def_attribute :first_name
78
+ def_attribute :last_name
79
+ def_attribute :status
80
+
81
+ undefine_attribute :name
82
+ end
83
+ ```
84
+
85
+ Then, update the process to manage student duplicates. Update function `create_student`
86
+
87
+ *The generic process handlers:*
88
+
89
+ ``` ruby
90
+ class StudentsProcess
91
+ def create_student(sObjectType, hParams)
92
+ PrcLib::state ("Running creation process for object '%s' = '%s'" % [sObjectType, hParams[:student_name] ])
93
+
94
+ # config object is a reference to runtime/config data.
95
+ oList = Query(sObjectType, {:name => hParams[:student_name]})
96
+ case oList.length
97
+ when 0
98
+ oObject = controller_create(sObjectType)
99
+ raise "Student '%s' not created." % hParams[:student_name] if oObject.nil?
100
+ PrcLib::info ("'%s': '%s' created with id %s" % [sObjectType, hParams[:student_name], oObject[:id]])
101
+ when 1
102
+ oObject = oList[0]
103
+ PrcLib::info ("'%s': '%s' loaded with id %s" % [sObjectType, hParams[:student_name], oObject[:id]])
104
+ else
105
+ oObject = oList[0]
106
+ PrcLib::warning("More than one student named '%s' is found: %s records. Selecting the first one and removing duplicates." % [hParams[:student_name], oList.length])
107
+ iCount = 0
108
+ oList[1..-1].each { | elem |
109
+ register(elem)
110
+ iCount += controller_delete(sObjectType)
111
+ }
112
+ PrcLib::info ("'%s': %s duplicated '%s' removed. First loaded with id %s" % [sObjectType, iCount, hParams[:student_name], oObject[:id]])
113
+ end
114
+ oObject
115
+ end
116
+ end
117
+ ```
118
+
119
+ Here you see that we query, check list, create if missing, or delete if duplicates found.
120
+ You can run it now, as we still uses mock controller. It should work.
121
+
122
+ ##### File `students.rb`
123
+
124
+ Now, let's update the main to be close to what we have on `examples/yaml_students/students.rb`
125
+
126
+ This is a simple basic translation of `examples/yaml_students/students.rb`
127
+
128
+ ``` ruby
129
+ #!/usr/bin/env ruby
130
+
131
+ $APP_PATH = File.dirname(__FILE__)
132
+ require 'lorj'
133
+ require 'ansi'
134
+
135
+ # If you want to see what is happening in the framework, uncomment debug settings.
136
+ # PrcLib.level = Logger::DEBUG # Printed out to your console.
137
+ # PrcLib.core_level = 3 # framework debug levels. Values between 0 to 5.
138
+
139
+ # Initialize the framework
140
+ hProcesses = [ File.join($APP_PATH, 'process', 'students.rb')]
141
+
142
+ # You can try with mock instead. uncomment the next line and comment 2 next lines.
143
+ #~ oStudentCore = Lorj::Core.new( nil, hProcesses, :mock)
144
+ oStudentCore = Lorj::Core.new( nil, hProcesses, File.join($APP_PATH, 'controller', 'yaml_students.rb'))
145
+ oStudentCore.Create(:connection, :connection_string => "/tmp/students.yaml")
146
+
147
+ puts ANSI.bold("Create 1st student:")
148
+
149
+ oStudentCore.Create(:student, {
150
+ student_name: 'Robert Redford',
151
+ first_name: 'Robert',
152
+ last_name: 'Redford',
153
+ course: 'Art Comedy'
154
+ })
155
+
156
+ puts ANSI.bold("Create 2nd student:")
157
+ oStudentCore.Create(:student, {
158
+ student_name: 'Anthony Hopkins',
159
+ first_name: 'Anthony',
160
+ last_name: 'Hopkins',
161
+ course: 'Art Drama'
162
+ })
163
+
164
+ puts ANSI.bold("Create 3rd student:")
165
+ oStudentCore.Create(:student, {
166
+ student_name: "Marilyn Monroe",
167
+ first_name: 'Marilyn',
168
+ last_name: 'Monroe',
169
+ course: 'Art Drama'
170
+ })
171
+
172
+ puts ANSI.bold("Create mistake")
173
+ oStudentCore.Create(:student, {
174
+ :student_name => "Anthony Mistake",
175
+ :first_name => 'Anthony',
176
+ :last_name => 'Mistake',
177
+ :course => 'what ever you want!!!'
178
+ })
179
+
180
+ # Because the last student was the mistake one, we can directly delete it.
181
+ # Usually, we use get instead.
182
+ puts ANSI.bold("Remove mistake")
183
+ oStudentCore.Delete(:student)
184
+
185
+ puts ANSI.bold("List of students for 'Art Drama':")
186
+ puts oStudentCore.Query(:student, { :course => "Art Drama"}).to_a
187
+
188
+ puts ANSI.bold("Deleted students:")
189
+ puts oStudentCore.Query(:student,{ :status => :removed}).to_a
190
+ ```
191
+
192
+ We have reproduced the code. Note that there is no if while creating. It is embedded in the create_student process.
193
+
194
+ ##### File `controller/yaml_students_controller.rb`
195
+
196
+ We need to write the controller part, now. As I said, it is like a wrapper. Let's have a look:
197
+
198
+ *The controller code:*
199
+
200
+ ``` ruby
201
+ # declare yaml student API to the controller
202
+ cur_file = File.expand_path(File.join(File.dirname(File.dirname(__FILE__)), "..", "yaml_students", 'yaml_students.rb'))
203
+ require cur_file
204
+
205
+ # The controller is a combination of 2 elements:
206
+ # - Controller class
207
+ # Code which will interfere with the external API.
208
+ #
209
+ # The file name must respect the name of the class. 1st letter already capitalized and letter after _ is capitalized.
210
+ # file: my_code.rb => needs to create MyCodeController class
211
+ #
212
+ # - Definition class
213
+ # This class declare any kind of mapping or additional fields to consider.
214
+ # Additionnal fields are unknow by the process. So, those fields will needs to be setup before.
215
+ #
216
+ # file name convention is identical than controller class.
217
+ # file: my_code.rb => needs to create MyCode class
218
+
219
+ class YamlStudentsController
220
+ def initialize()
221
+ @@valid_attributes = [:name, :first_name, :last_name, :id, :status, :training]
222
+ end
223
+
224
+ def create(sObjectType, hParams)
225
+ case sObjectType
226
+ when :connection
227
+ required?(hParams, :hdata, :file_name)
228
+ YamlSchool.new(hParams[:hdata, :file_name])
229
+ when :student
230
+ required?(hParams, :connection)
231
+ required?(hParams, :student_name)
232
+
233
+ # We use the hdata built by the lorj. See set_hdata in the next file.
234
+ hParams[:connection].create_student(hParams[:student_name], hParams[:hdata])
235
+ else
236
+ Error "'%s' is not a valid object for 'create'" % sObjectType
237
+ end
238
+ end
239
+
240
+ # This function return a collection which have to provide:
241
+ # functions: [], length, each
242
+ def query(sObjectType, sQuery, hParams)
243
+ case sObjectType
244
+ when :student
245
+ required?(hParams, :connection)
246
+
247
+ hParams[:connection].query_student(sQuery)
248
+ else
249
+ Error "'%s' is not a valid object for 'create'" % sObjectType
250
+ end
251
+
252
+ end
253
+
254
+ def delete(sObjectType, hParams)
255
+ case sObjectType
256
+ when :student
257
+ required?(hParams, :connection)
258
+
259
+ hParams[:connection].delete_student(hParams[sObjectType][:id])
260
+ else
261
+ Error "'%s' is not a valid object for 'create'" % sObjectType
262
+ end
263
+ end
264
+
265
+ def get_attr(oControlerObject, key)
266
+ # This controller function read the data and
267
+ # extract the information requested by the framework.
268
+ # Those data will be mapped to the process data model.
269
+ # The key is an array, to get data from a level tree.
270
+ # [data_l1, data_l2, data_l3] => should retrieve data from structure
271
+ # like data[ data_l2 [ data_l3 ] ]
272
+ begin
273
+ attributes = oControlerObject
274
+ raise "get_attr: attribute '%s' is unknown in '%s'. Valid one are : '%s'",
275
+ key[0], oControlerObject.class,
276
+ @@valid_attributes unless @@valid_attributes.include?(key[0])
277
+ Lorj::rh_get(attributes, key)
278
+ rescue => e
279
+ Error "get_attr: Unable to map '%s'. %s" % [key, e.message]
280
+ end
281
+ end
282
+
283
+ def set_attr(oControlerObject, key, value)
284
+ begin
285
+ attributes = oControlerObject
286
+ raise "set_attr: attribute '%s' is unknown in '%s'. Valid one are : '%s'",
287
+ key[0], oControlerObject.class,
288
+ @@valid_attributes unless @@valid_attributes.include?(key[0])
289
+ Lorj::rh_set(attributes, value, key)
290
+ rescue => e
291
+ Error "set_attr: Unable to map '%s' on '%s'" % [key, sObjectType]
292
+ end
293
+ end
294
+
295
+ def update(sObjectType, oObject, hParams)
296
+ case sObjectType
297
+ when :student
298
+ required?(hParams, :connection)
299
+
300
+ hParams[:connection].update_student(oObject)
301
+ else
302
+ Error "'%s' is not a valid object for 'create'" % sObjectType
303
+ end
304
+ end
305
+
306
+ end
307
+
308
+ ```
309
+ In short, we wrap:
310
+
311
+ - create with YamlSchool.create_student
312
+ - delete with YamlSchool.delete_student
313
+ - query with YamlSchool.query_student
314
+ - update with YamlSchool.update_student
315
+
316
+ And we have defined 2 additional functions
317
+
318
+ - get_attr: to extract data from a YamlSchool Object
319
+ - set_attr: to set data to a YamlSchool Object
320
+
321
+ ##### File `controller/yaml_students.rb`
322
+
323
+ And we need to write some mapping stuff to the controller. We have to add this
324
+
325
+ *The controller definition:*
326
+
327
+ ``` ruby
328
+ class YamlStudents
329
+ # This is a new object which is known by the controller only.
330
+ # Used to open the yaml file. Generically, I named it :connection.
331
+ # But this can be any name you want. Only the controller will deal with it.
332
+ define_obj(:connection,{
333
+ :create_e => :controller_create # Nothing complex to do. So, simply call the controller create.
334
+ })
335
+
336
+ obj_needs :data, :connection_string, :mapping => :file_name
337
+ undefine_attribute :id # Do not return any predefined ID
338
+ undefine_attribute :name # Do not return any predefined NAME
339
+
340
+ # The student model have to be expanded.
341
+ define_obj(:student)
342
+ # It requires to create a connection to the data, ie opening the yaml file.
343
+ # So, before working with the :student object, the controller requires a connection
344
+ # This connection will be loaded in the memory and provided to the controller
345
+ # when needed.
346
+ obj_needs :CloudObject, :connection
347
+
348
+ # To simplify controller wrapper, we use hdata built by lorj, and passed to the API
349
+ # This hdata is a hash containing mapped data, thanks to set_hdata.
350
+ set_hdata :first_name
351
+ set_hdata :last_name
352
+ # Instead of 'course', the yaml API uses 'training'
353
+ set_hdata :course, :mapping => :training
354
+
355
+ get_attr_mapping :course, :training
356
+ # instead of 'student_name', the yaml API uses 'name'
357
+ get_attr_mapping :student_name, :name
358
+
359
+ # This controller will know how to manage a student file with those data.
360
+ # But note that the file can have a lot of more data than what the process
361
+ # usually manage. It is up to you to increase your process to manage more data.
362
+ # Then each controller may need to define mapping fields.
363
+ end
364
+ ```
365
+
366
+ That's it!
367
+
368
+ #####typical output:
369
+ $ example/students_3/students.rb
370
+ WARNING: PrcLib.app_defaults is not set. Application defaults won't be loaded.
371
+ Create 1st student:
372
+ Create 2nd student:
373
+ Create 3rd student:
374
+ Create mistake
375
+ Student created '{:id=>3, :course=>"what ever you want!!!", :student_name=>"Anthony Mistake", :first_name=>"Anthony", :last_name=>"Mistake", :status=>:active}'
376
+ Remove mistake
377
+ Wrong student to remove: 3 = Anthony Mistake
378
+ List of students for 'Art Drama':
379
+ {:id=>1, :course=>"Art Drama", :student_name=>"Anthony Hopkins", :first_name=>"Anthony", :last_name=>"Hopkins", :status=>:active}
380
+ {:id=>2, :course=>"Art Drama", :student_name=>"Marilyn Monroe", :first_name=>"Marilyn", :last_name=>"Monroe", :status=>:active}
381
+ Deleted students:
382
+ {:id=>3, :course=>"what ever you want!!!", :student_name=>"Anthony Mistake", :first_name=>"Anthony", :last_name=>"Mistake", :status=>:removed}