lore 0.4.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 (90) hide show
  1. data/LICENSE +19 -0
  2. data/README +74 -0
  3. data/aspect.rb +80 -0
  4. data/behaviours/lockable.rb +41 -0
  5. data/behaviours/movable.rb +54 -0
  6. data/behaviours/versioned.rb +24 -0
  7. data/benchmark.rb +193 -0
  8. data/bits.rb +52 -0
  9. data/cache/abstract_entity_cache.rb +82 -0
  10. data/cache/bits.rb +22 -0
  11. data/cache/cacheable.rb +202 -0
  12. data/cache/cached_entities.rb +116 -0
  13. data/cache/file_index.rb +35 -0
  14. data/cache/mmap_entity_cache.rb +67 -0
  15. data/clause.rb +528 -0
  16. data/connection.rb +155 -0
  17. data/custom_functions.sql +14 -0
  18. data/exception/ambiguous_attribute.rb +14 -0
  19. data/exception/cache_exception.rb +30 -0
  20. data/exception/invalid_klass_parameters.rb +63 -0
  21. data/exception/invalid_parameter.rb +42 -0
  22. data/exception/unknown_typecode.rb +19 -0
  23. data/file_index.sql +56 -0
  24. data/gui/erb_template.rb +79 -0
  25. data/gui/erb_template_helpers.rhtml +19 -0
  26. data/gui/form.rb +314 -0
  27. data/gui/form_element.rb +676 -0
  28. data/gui/form_generator.rb +151 -0
  29. data/gui/templates/button.rhtml +2 -0
  30. data/gui/templates/checkbox.rhtml +3 -0
  31. data/gui/templates/checkbox_row.rhtml +1 -0
  32. data/gui/templates/file.rhtml +2 -0
  33. data/gui/templates/file_readonly.rhtml +3 -0
  34. data/gui/templates/form_element.rhtml +5 -0
  35. data/gui/templates/form_element_horizontal.rhtml +3 -0
  36. data/gui/templates/form_element_listed.rhtml +8 -0
  37. data/gui/templates/form_table.rhtml +3 -0
  38. data/gui/templates/form_table_blank.rhtml +3 -0
  39. data/gui/templates/form_table_horizontal.rhtml +8 -0
  40. data/gui/templates/password.rhtml +2 -0
  41. data/gui/templates/password_readonly.rhtml +3 -0
  42. data/gui/templates/radio.rhtml +1 -0
  43. data/gui/templates/radio_row.rhtml +1 -0
  44. data/gui/templates/select.rhtml +23 -0
  45. data/gui/templates/text.rhtml +2 -0
  46. data/gui/templates/text_readonly.rhtml +3 -0
  47. data/gui/templates/textarea.rhtml +3 -0
  48. data/gui/templates/textarea_readonly.rhtml +4 -0
  49. data/lore.gemspec +40 -0
  50. data/lore.rb +94 -0
  51. data/migration.rb +48 -0
  52. data/model.rb +139 -0
  53. data/model_factory.rb +202 -0
  54. data/model_shortcuts.rb +16 -0
  55. data/query_shortcuts.rb +367 -0
  56. data/reserved_methods.txt +3 -0
  57. data/result.rb +100 -0
  58. data/symbol.rb +58 -0
  59. data/table_accessor.rb +1926 -0
  60. data/table_deleter.rb +115 -0
  61. data/table_inserter.rb +168 -0
  62. data/table_instance.rb +384 -0
  63. data/table_selector.rb +314 -0
  64. data/table_updater.rb +155 -0
  65. data/test/README +31 -0
  66. data/test/env.rb +5 -0
  67. data/test/lore_test.log +8218 -0
  68. data/test/model.rb +142 -0
  69. data/test/prepare.rb +37 -0
  70. data/test/tc_aspect.rb +58 -0
  71. data/test/tc_cache.rb +80 -0
  72. data/test/tc_clause.rb +104 -0
  73. data/test/tc_deep_inheritance.rb +49 -0
  74. data/test/tc_factory.rb +57 -0
  75. data/test/tc_filter.rb +37 -0
  76. data/test/tc_form.rb +32 -0
  77. data/test/tc_model.rb +86 -0
  78. data/test/tc_prepare.rb +45 -0
  79. data/test/tc_refined_query.rb +88 -0
  80. data/test/tc_table_accessor.rb +265 -0
  81. data/test/test.log +181 -0
  82. data/test/test_db.sql +400 -0
  83. data/test/ts_lore.rb +49 -0
  84. data/types.rb +55 -0
  85. data/validation/message.rb +60 -0
  86. data/validation/parameter_validator.rb +104 -0
  87. data/validation/reason.rb +54 -0
  88. data/validation/type_validator.rb +91 -0
  89. data/validation.rb +65 -0
  90. metadata +170 -0
@@ -0,0 +1,30 @@
1
+
2
+ require('lore/cache/bits')
3
+
4
+ module Lore
5
+ module Cache
6
+
7
+ class Cache_Read_Exception < ::Exception
8
+
9
+ def initialize(klass_name, controller, mode, keys)
10
+
11
+ @message = 'PStore file does not exist: [' << Lore::Cache.store_name(klass_name, controller, mode, keys) << ']'
12
+
13
+ end # def
14
+
15
+ end # class
16
+
17
+ class Cache_Write_Exception < ::Exception
18
+
19
+ def initialize(klass_name, controller, mode, keys)
20
+
21
+ @message = 'Error when trying to cache [' << Lore::Cache.store_name(klass_name, controller, mode, keys) << ']'
22
+ @message += '(is caching enabled for this controller?)'
23
+
24
+ end # def
25
+
26
+ end # class
27
+
28
+
29
+ end # module
30
+ end # module
@@ -0,0 +1,63 @@
1
+
2
+ module Lore
3
+ module Exception
4
+
5
+ # Usage:
6
+ #
7
+ # raise Lore::Exception::Invalid_Klass_Parameters.new(The_Model, {
8
+ # # Generic error. Example: :user_id => Lore.integer
9
+ # :table_foo => Invalid_Parameters.new( :the_attribute => :error_type )
10
+ # # Constraint error. Example: :email => :format
11
+ # :table bar => Unmet_Constraints.new( :the_attribute => :error_type )
12
+ # # Type error. Example: :user_id => Lore.integer or :user_id => :missing
13
+ # :table_batz => Invalid_Types.new( :the_attribute => :error_type )
14
+ # })
15
+ #
16
+ class Invalid_Klass_Parameters < ::Exception
17
+
18
+ attr_reader :invalid_parameters
19
+ attr_reader :invalid_klass
20
+
21
+ def initialize(klass, invalid_params_hash)
22
+
23
+ @logger = Lore.logger
24
+ # Instances of Exception::Invalid_Parameters
25
+ @invalid_parameters = invalid_params_hash
26
+ @invalid_klass = klass
27
+
28
+ end
29
+
30
+ def log()
31
+
32
+ @logger.error('Invalid parameters for klass '+@invalid_klass.to_s+': ')
33
+ @logger.error('Invalid parameters: ')
34
+ @logger.error(@invalid_parameters.inspect)
35
+ @logger.error('Explicit attributes: ')
36
+ @logger.error(@invalid_klass.get_explicit_attributes.inspect)
37
+
38
+ end
39
+
40
+ def serialize() # {{{
41
+
42
+ serials = {}
43
+ @invalid_parameters.each_pair { |table, invalid_param|
44
+ serials[table] = invalid_param.serialize
45
+ }
46
+ return serials
47
+
48
+ end # def }}}
49
+
50
+ def inspect()
51
+ 'Model('+@invalid_klass.to_s+') => '+
52
+ @invalid_parameters.inspect+
53
+ ' Explicit: '+
54
+ @invalid_klass.get_explicit_attributes.inspect
55
+ end
56
+ alias explain serialize
57
+
58
+ end
59
+
60
+
61
+ end # module
62
+ end # module
63
+
@@ -0,0 +1,42 @@
1
+
2
+ module Lore
3
+ module Exception
4
+
5
+ class Invalid_Parameters < ::Exception
6
+
7
+ attr_reader :invalid_params, :reason
8
+
9
+ def initialize(invalid_params)
10
+ @invalid_params = invalid_params
11
+ @reason = :invalid
12
+ end
13
+ alias fields invalid_params
14
+
15
+ def serialize
16
+ result = {}
17
+ @invalid_params.each_pair { |field, type|
18
+ result[field] = type
19
+ }
20
+ result
21
+ end
22
+ alias serialize inspect
23
+
24
+ end
25
+
26
+ class Invalid_Types < Invalid_Parameters
27
+ def initialize(invalid_params)
28
+ super(invalid_params)
29
+ @reason = :type
30
+ end
31
+ end
32
+
33
+ class Unmet_Constraints < Invalid_Parameters
34
+ def initialize(invalid_params)
35
+ super(invalid_params)
36
+ @reason = :constraint
37
+ end
38
+ end
39
+
40
+
41
+ end # module
42
+ end # module
@@ -0,0 +1,19 @@
1
+
2
+ module Lore
3
+ module Exception
4
+
5
+ class Unknown_Typecode < ::Exception
6
+
7
+ attr_reader :code
8
+
9
+ def initialize(_code)
10
+
11
+ @code = _code
12
+ @message = 'Unknown PGSQL type: ' + _code.to_s
13
+
14
+ end
15
+
16
+ end
17
+
18
+ end # module
19
+ end # module
data/file_index.sql ADDED
@@ -0,0 +1,56 @@
1
+
2
+ CREATE TABLE file_index (
3
+ file_index_id integer NOT NULL,
4
+ model character varying(100),
5
+ file character varying(255)
6
+ );
7
+
8
+
9
+ ALTER TABLE public.file_index OWNER TO fuchsto;
10
+
11
+ CREATE SEQUENCE file_index_id_seq
12
+ START WITH 1
13
+ INCREMENT BY 1
14
+ NO MAXVALUE
15
+ NO MINVALUE
16
+ CACHE 1;
17
+
18
+
19
+ ALTER TABLE public.file_index_id_seq OWNER TO fuchsto;
20
+
21
+ --
22
+ -- Name: public; Type: ACL; Schema: -; Owner: postgres
23
+ --
24
+
25
+ REVOKE ALL ON SCHEMA public FROM PUBLIC;
26
+ REVOKE ALL ON SCHEMA public FROM postgres;
27
+ GRANT ALL ON SCHEMA public TO postgres;
28
+ GRANT ALL ON SCHEMA public TO PUBLIC;
29
+
30
+
31
+ --
32
+ -- Name: file_index; Type: ACL; Schema: public; Owner: fuchsto
33
+ --
34
+
35
+ REVOKE ALL ON TABLE file_index FROM PUBLIC;
36
+ REVOKE ALL ON TABLE file_index FROM fuchsto;
37
+ GRANT ALL ON TABLE file_index TO fuchsto;
38
+ GRANT ALL ON TABLE file_index TO cuba;
39
+ GRANT ALL ON TABLE file_index TO lore;
40
+
41
+
42
+ --
43
+ -- Name: file_index_id_seq; Type: ACL; Schema: public; Owner: fuchsto
44
+ --
45
+
46
+ REVOKE ALL ON SEQUENCE file_index_id_seq FROM PUBLIC;
47
+ REVOKE ALL ON SEQUENCE file_index_id_seq FROM fuchsto;
48
+ GRANT ALL ON SEQUENCE file_index_id_seq TO fuchsto;
49
+ GRANT ALL ON SEQUENCE file_index_id_seq TO lore;
50
+ GRANT ALL ON SEQUENCE file_index_id_seq TO cuba;
51
+
52
+
53
+ --
54
+ -- PostgreSQL database dump complete
55
+ --
56
+
@@ -0,0 +1,79 @@
1
+
2
+ require('lore/lore')
3
+ require('logger')
4
+ require('erb')
5
+
6
+ module Lore
7
+ module GUI
8
+
9
+ class ERB_Binding_Params
10
+
11
+ def initialize(param_hash)
12
+ @params = Hash.new
13
+ param_hash.each_pair { |key,value|
14
+ @params[key.to_s.intern] = value
15
+ }
16
+ end
17
+
18
+ def get(param)
19
+ @params[param]
20
+ end
21
+
22
+ def param(param)
23
+ @params[param]
24
+ end
25
+
26
+ def method_missing(method)
27
+ @params[method]
28
+ end
29
+
30
+ end
31
+
32
+ class ERB_Template
33
+
34
+ public
35
+
36
+ def initialize(template_path, param_hash={}, from=:backend)
37
+
38
+ @logger = Lore.logger
39
+
40
+ @template = ''
41
+ IO.foreach(Lore.path + 'gui/erb_template_helpers.rhtml') { |line|
42
+ @template << line
43
+ }
44
+ template_path = template_path.to_s << '.rhtml' if template_path.instance_of? Symbol
45
+ IO.foreach(Lore.path + 'gui/templates/' << template_path) { |line|
46
+ @template << line
47
+ }
48
+
49
+ @logger.debug('Template: ' << template_path)
50
+
51
+ @erb = ERB.new(@template)
52
+
53
+ @binding = binding_for(ERB_Binding_Params.new(param_hash))
54
+
55
+ end
56
+
57
+ def set_data(param_hash)
58
+ @binding = binding_for(ERB_Binding_Params.new(param_hash))
59
+ end
60
+
61
+ def string
62
+ @erb.result(@binding)
63
+ end
64
+
65
+ def print
66
+ puts @erb.result(@binding)
67
+ end
68
+
69
+ protected
70
+
71
+ def binding_for(params)
72
+ binding
73
+ end
74
+
75
+
76
+ end # class
77
+
78
+ end # module
79
+ end # module
@@ -0,0 +1,19 @@
1
+ <%
2
+
3
+ def tag_attributes(attrib_hash)
4
+ return '' if attrib_hash.nil?
5
+ string = ''
6
+ attrib_hash.each_pair { |name, value|
7
+ string << name.to_s
8
+ string << '="' << value.to_s
9
+ string << '" '
10
+ }
11
+ string
12
+ end
13
+
14
+ @params = params
15
+ def method_missing(method)
16
+ @params.get(method)
17
+ end
18
+
19
+ %>
data/gui/form.rb ADDED
@@ -0,0 +1,314 @@
1
+
2
+ require('lore/clause')
3
+ require 'lore/gui/form_element'
4
+
5
+ module Lore
6
+ module GUI
7
+
8
+ # Form class returned by Cuba::GUI::Form_Generator.
9
+ # Usage:
10
+ #
11
+ # generator = Form_Generator.new(Table_Accessor, Lang, :readonly | :mutable)
12
+ # form = generator.generate
13
+ #
14
+ # Setting templates is optional (uses System_Templates 'form/element.amr.html'
15
+ # and 'form/table.arm.html' by default):
16
+ #
17
+ # form.element_template Some_Template.new('template/element.amr.html')
18
+ # form.form_template Some_Template.new('template/table.amr.html')
19
+ #
20
+ # Set a form title (optional):
21
+ #
22
+ # form.set_title('An example form')
23
+ #
24
+ # Fill form values if present:
25
+ #
26
+ # values = [Some Cuba::Attributes hash like $cb__libparams]
27
+ # form.set_values(values)
28
+ #
29
+ # Add additional hidden fields Form_Generator can't resolve itself:
30
+ #
31
+ # form.add_hidden(Table_Accessor.table_name, :attribute_name, value)
32
+ #
33
+ # Add buttons:
34
+ #
35
+ # form.add_button(:submit, 'click here to submit data')
36
+ # form.add_button(:clear, 'click here to clear form')
37
+ #
38
+ # Configure attribute order and grouping (optional). See method
39
+ # documentation for #set_groups for details:
40
+ #
41
+ # form.set_groups(attribute_array)
42
+ #
43
+ # form.print # alias for puts form.string
44
+ #
45
+ class Form
46
+
47
+ attr_accessor :element_template, :form_template, :form_values
48
+
49
+ @@logger = Lore.logger
50
+
51
+ def initialize # {{{
52
+
53
+ @elements = Array.new
54
+ @buttons = Array.new
55
+ @indexed_elements = Hash.new
56
+ @element_template = ERB_Template.new('form_element.rhtml')
57
+ @form_template = ERB_Template.new('form_table.rhtml')
58
+ @form_values = Hash.new
59
+ @element_groups = nil
60
+ @hidden_fields = Array.new
61
+ @title = nil
62
+
63
+ end # }}}
64
+
65
+ # adders and setters # {{{
66
+ def add(form_element)
67
+ if form_element.instance_of? Hidden then
68
+ @hidden_fields.push(form_element)
69
+ else
70
+ if form_element.attribute_table then
71
+ index = form_element.attribute_table+'.'+form_element.attribute_name
72
+ else
73
+ index = form_element.attribute_name
74
+ end
75
+ # If there is an element for this attribute present already, delete
76
+ # it and use the new one only:
77
+ if !@indexed_elements[index].nil? then
78
+ @elements.delete_if { |e| e.attribute_table == form_element.attribute_table &&
79
+ e.attribute_name == form_element.attribute_name }
80
+ end
81
+ @indexed_elements[index] = form_element
82
+ @elements.push(form_element)
83
+ end
84
+ end
85
+
86
+ def add_duplicate(form_element)
87
+ if form_element.instance_of? Hidden then
88
+ @hidden_fields.push(form_element)
89
+ else
90
+ index = form_element.attribute_table+'.'+form_element.attribute_name
91
+ # If there is an element for this attribute present already, delete
92
+ # it and use the new one only:
93
+ @indexed_elements[index] = form_element
94
+ @elements.push(form_element)
95
+ end
96
+ end
97
+
98
+ def set_readonly(*attributes)
99
+ attributes.each { |a|
100
+ @indexed_elements[a.to_s].set_mode(:readonly)
101
+ }
102
+ end
103
+
104
+ # Add additional hidden fields Form_Generator can't resolve itself:
105
+ #
106
+ # form.add_hidden(Table_Accessor.table_name, :attribute_name, value)
107
+ #
108
+ def add_hidden(name, value=nil)
109
+ if name.instance_of? Lore::Clause then
110
+ value = value.to_s
111
+ name_parts = name.to_s.split('.')
112
+ table = name_parts[0..1].join('.')
113
+ name = name_parts[2]
114
+ else
115
+ table = nil
116
+ name = name.to_s
117
+ end
118
+ hidden = Hidden.new(table, name.to_s)
119
+ if !value.nil? then
120
+ hidden.set_attribute_value(value.to_s)
121
+ end
122
+ @hidden_fields.push(hidden)
123
+ end
124
+
125
+ def add_hidden_fields(params={})
126
+ params.each_pair { |k,v|
127
+ add_hidden(k, v)
128
+ }
129
+ end
130
+
131
+ def drop_hidden_fields
132
+ @hidden_fields = []
133
+ end
134
+
135
+ # Add buttons:
136
+ #
137
+ # form.add_button(:submit, 'click here to submit data')
138
+ # form.add_button(:clear, 'click here to clear form')
139
+ #
140
+ def add_button(type, label)
141
+ button = Button.new(type, label)
142
+ @buttons.push(button)
143
+ end
144
+
145
+ # Fill form values if present:
146
+ #
147
+ # values = [Some Cuba::Attributes hash like $cb__libparams]
148
+ # form.set_values(values)
149
+ #
150
+ def set_values(values)
151
+ @form_values = values
152
+ end
153
+
154
+ def [](key)
155
+ @form_values[key.to_s]
156
+ end
157
+
158
+ def []=(key, value)
159
+ @form_values[key.to_s] = value
160
+ end
161
+
162
+ def values
163
+ @form_values
164
+ end
165
+
166
+ def keys
167
+ @form_values.keys
168
+ end
169
+
170
+ # Configure attribute order and grouping (optional).
171
+ # Array argument is a one- or two-dimensional array of
172
+ # full attribute names this form should print. This way,
173
+ # order of input fields can be specified, and attributes
174
+ # can be filtered. Two-dimensional arrays provide grouping
175
+ # of form elements. Example:
176
+ #
177
+ # qttribute_array =
178
+ # [
179
+ # [ Klass_A.foo, Klass_A.bar ],
180
+ # [ Klass_B.wombat, Klass_C.bla ]
181
+ # ]
182
+ #
183
+ # form.set_groups(attribute_array)
184
+ #
185
+ # Add filtered attribute as hidden field:
186
+ #
187
+ # form.add_hidden(Klass_A.table_name, :wombat)
188
+ #
189
+ def set_groups(groups)
190
+ if(groups.nil? || groups.at(0).nil?) then
191
+ @@logger.warn('Form groups are nil or empty')
192
+ return
193
+ end
194
+ groups.map! { |entry|
195
+ if entry.instance_of? Array then
196
+ entry.map! { |field| field.to_s }
197
+ else
198
+ entry.to_s
199
+ end
200
+ }
201
+ @@logger.debug('Form groups set: '+groups.inspect)
202
+ @element_groups = groups
203
+ end
204
+
205
+ # Set a form title (optional):
206
+ #
207
+ # form.set_title('An example form')
208
+ #
209
+ def set_title(title)
210
+ @title = title
211
+ end
212
+
213
+ # end adders / setters }}}
214
+
215
+ # Return form as XHTML string based on current configuration
216
+ #
217
+ def string # {{{
218
+
219
+ elements = ''
220
+
221
+ if !@title.nil? then
222
+ title_string = '<div class="form_header">'+@title.to_s+'</div>'
223
+ else
224
+ title_string = ''
225
+ end
226
+
227
+ if @element_groups.nil? then
228
+ @elements.each { |element|
229
+ elements += process_element(element)
230
+ }
231
+ else
232
+ @element_groups.each { |attribs|
233
+ group = ''
234
+ attribs.each { |attrib|
235
+ attrib = attrib.to_s
236
+ if !@indexed_elements[attrib].nil? then
237
+ element = @indexed_elements[attrib]
238
+ group += process_element(element)
239
+ end
240
+ }
241
+ if attribs.instance_of? Array then
242
+ elements += '<div class="form_delimiter"></div>'+group
243
+ else
244
+ elements += group
245
+ end
246
+ }
247
+ # Check for explicit (expected/required) attributes
248
+ # group configuration doesn't contain. Add those as
249
+ # hidden field:
250
+ # TODO: Cannot be realized in current solution!
251
+
252
+ end
253
+ @form_template.set_data({
254
+ :form => elements
255
+ })
256
+
257
+ buttons = ''
258
+ @buttons.each { |button|
259
+ data = {
260
+ :label => '',
261
+ :element => button.string
262
+ }
263
+ @element_template.set_data(data)
264
+ buttons += @element_template.string
265
+ }
266
+
267
+ hidden_fields_string = ''
268
+ @hidden_fields.each { |element|
269
+ set_element_value(element)
270
+ hidden_fields_string += element.string
271
+ }
272
+
273
+ result = title_string + hidden_fields_string + @form_template.string + buttons
274
+
275
+ return result
276
+
277
+ end # }}}
278
+
279
+ # Alias for puts form.string
280
+ def print
281
+ puts string()
282
+ end
283
+
284
+ private
285
+
286
+ def set_element_value(element) # {{{
287
+ if !@form_values[element.attribute_name].nil? then
288
+ value = @form_values[element.attribute_name]
289
+ element.set_attribute_value(value)
290
+ elsif !@form_values[element.attribute_table.to_s+'.'+element.attribute_name].nil? then
291
+ value = @form_values[element.attribute_table+'.'+element.attribute_name]
292
+ element.set_attribute_value(value)
293
+ end
294
+ end # }}}
295
+
296
+ def process_element(element) # {{{
297
+
298
+ set_element_value(element)
299
+
300
+ data = {
301
+ :label => "<label id=\"#{element.attribute_id}_label\" for=\"#{element.attribute_id}\">#{element.label}</label>",
302
+ :element => element.string,
303
+ :element_obj => element
304
+ }
305
+ @element_template.set_data(data)
306
+
307
+ return @element_template.string
308
+
309
+ end # }}}
310
+
311
+ end # class
312
+
313
+ end # module
314
+ end # module