lorj 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
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}