lore 0.4.8 → 0.9.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 (111) hide show
  1. data/Manifest.txt +16 -7
  2. data/README.rdoc +91 -0
  3. data/benchmark/benchmark.sql +11 -0
  4. data/benchmark/results.txt +28 -0
  5. data/benchmark/select.rb +352 -0
  6. data/lib/lore.rb +22 -8
  7. data/lib/lore/adapters/context.rb +64 -0
  8. data/lib/lore/adapters/postgres-pr.rb +6 -0
  9. data/lib/lore/adapters/postgres-pr/connection.rb +93 -0
  10. data/lib/lore/adapters/postgres-pr/result.rb +63 -0
  11. data/lib/lore/{types.rb → adapters/postgres-pr/types.rb} +36 -0
  12. data/lib/lore/adapters/postgres.rb +24 -0
  13. data/lib/lore/adapters/postgres/connection.rb +81 -0
  14. data/lib/lore/adapters/postgres/result.rb +82 -0
  15. data/lib/lore/adapters/postgres/types.rb +91 -0
  16. data/lib/lore/bits.rb +18 -0
  17. data/lib/lore/cache/abstract_entity_cache.rb +2 -1
  18. data/lib/lore/cache/cacheable.rb +12 -177
  19. data/lib/lore/cache/memcache_entity_cache.rb +89 -0
  20. data/lib/lore/cache/memory_entity_cache.rb +77 -0
  21. data/lib/lore/cache/mmap_entity_cache.rb +2 -2
  22. data/lib/lore/cache/mmap_entity_cache_bork.rb +86 -0
  23. data/lib/lore/clause.rb +107 -35
  24. data/lib/lore/{exception → exceptions}/ambiguous_attribute.rb +2 -2
  25. data/lib/lore/{exception → exceptions}/cache_exception.rb +1 -1
  26. data/lib/lore/exceptions/database_exception.rb +16 -0
  27. data/lib/lore/{exception/invalid_parameter.rb → exceptions/invalid_field.rb} +7 -4
  28. data/lib/lore/exceptions/unknown_type.rb +18 -0
  29. data/lib/lore/exceptions/validation_failure.rb +71 -0
  30. data/lib/lore/gui/form_generator.rb +109 -60
  31. data/lib/lore/gui/lore_model_select_field.rb +1 -0
  32. data/lib/lore/migration.rb +84 -25
  33. data/lib/lore/model.rb +3 -18
  34. data/lib/lore/{aspect.rb → model/aspect.rb} +0 -0
  35. data/lib/lore/model/associations.rb +225 -0
  36. data/lib/lore/model/attribute_settings.rb +233 -0
  37. data/lib/lore/model/filters.rb +34 -0
  38. data/lib/lore/model/mockable.rb +62 -0
  39. data/lib/lore/{model_factory.rb → model/model_factory.rb} +68 -39
  40. data/lib/lore/model/model_instance.rb +382 -0
  41. data/lib/lore/{model_shortcuts.rb → model/model_shortcuts.rb} +7 -0
  42. data/lib/lore/model/polymorphic.rb +53 -0
  43. data/lib/lore/model/prepare.rb +97 -0
  44. data/lib/lore/model/table_accessor.rb +1016 -0
  45. data/lib/lore/query.rb +71 -0
  46. data/lib/lore/query_shortcuts.rb +43 -11
  47. data/lib/lore/strategies/table_delete.rb +115 -0
  48. data/lib/lore/strategies/table_insert.rb +146 -0
  49. data/lib/lore/strategies/table_select.rb +299 -0
  50. data/lib/lore/strategies/table_update.rb +155 -0
  51. data/lib/lore/validation/parameter_validator.rb +85 -26
  52. data/lib/lore/validation/type_validator.rb +34 -78
  53. data/{custom_models.rb → lore-0.9.2.gem} +0 -0
  54. data/lore.gemspec +26 -17
  55. data/spec/clause.rb +37 -0
  56. data/spec/fixtures/blank_models.rb +37 -0
  57. data/{test/model.rb → spec/fixtures/models.rb} +64 -41
  58. data/spec/fixtures/polymorphic_models.rb +68 -0
  59. data/spec/model_associations.rb +86 -0
  60. data/spec/model_create.rb +47 -0
  61. data/spec/model_definition.rb +151 -0
  62. data/spec/model_delete.rb +31 -0
  63. data/spec/model_inheritance.rb +50 -0
  64. data/spec/model_polymorphic.rb +85 -0
  65. data/spec/model_select.rb +101 -0
  66. data/spec/model_select_eager.rb +42 -0
  67. data/spec/model_union_select.rb +33 -0
  68. data/spec/model_update.rb +45 -0
  69. data/spec/model_validation.rb +20 -0
  70. data/spec/spec_db.sql +808 -0
  71. data/spec/spec_env.rb +19 -0
  72. data/spec/spec_helpers.rb +77 -0
  73. metadata +93 -82
  74. data/lib/lore/README.txt +0 -84
  75. data/lib/lore/behaviours/lockable.rb +0 -55
  76. data/lib/lore/behaviours/movable.rb +0 -72
  77. data/lib/lore/behaviours/paginated.rb +0 -31
  78. data/lib/lore/behaviours/versioned.rb +0 -36
  79. data/lib/lore/connection.rb +0 -152
  80. data/lib/lore/exception/invalid_klass_parameters.rb +0 -63
  81. data/lib/lore/exception/unknown_typecode.rb +0 -19
  82. data/lib/lore/result.rb +0 -119
  83. data/lib/lore/symbol.rb +0 -58
  84. data/lib/lore/table_accessor.rb +0 -1790
  85. data/lib/lore/table_deleter.rb +0 -116
  86. data/lib/lore/table_inserter.rb +0 -170
  87. data/lib/lore/table_instance.rb +0 -389
  88. data/lib/lore/table_selector.rb +0 -285
  89. data/lib/lore/table_updater.rb +0 -157
  90. data/lib/lore/validation.rb +0 -65
  91. data/lib/lore/validation/message.rb +0 -60
  92. data/lib/lore/validation/reason.rb +0 -52
  93. data/lore_test.log +0 -2366
  94. data/test/README +0 -31
  95. data/test/custom_models.rb +0 -18
  96. data/test/env.rb +0 -5
  97. data/test/prepare.rb +0 -37
  98. data/test/tc_aspect.rb +0 -58
  99. data/test/tc_cache.rb +0 -83
  100. data/test/tc_clause.rb +0 -104
  101. data/test/tc_deep_inheritance.rb +0 -49
  102. data/test/tc_factory.rb +0 -57
  103. data/test/tc_filter.rb +0 -37
  104. data/test/tc_form.rb +0 -32
  105. data/test/tc_model.rb +0 -140
  106. data/test/tc_prepare.rb +0 -44
  107. data/test/tc_refined_query.rb +0 -88
  108. data/test/tc_table_accessor.rb +0 -267
  109. data/test/tc_thread.rb +0 -100
  110. data/test/test_db.sql +0 -400
  111. data/test/test_lore.rb +0 -50
@@ -0,0 +1,155 @@
1
+
2
+ require('lore/bits')
3
+
4
+ module Lore
5
+
6
+ class Table_Update
7
+
8
+ @logger = Logger.new(Lore.logfile)
9
+
10
+ public
11
+
12
+ def initialize(accessor)
13
+ @accessor = accessor
14
+ @base_table = accessor.table_name
15
+ end
16
+
17
+ private
18
+
19
+ def atomic_update_query(accessor,
20
+ primary_key_values,
21
+ value_keys)
22
+ # {{{
23
+
24
+ return unless value_keys && value_keys.length > 0
25
+
26
+ table = accessor.table_name
27
+ # attributes = accessor.get_fields_flat
28
+ attributes = accessor.get_fields[table]
29
+ required = accessor.__attributes__.required[table]
30
+ required ||= {}
31
+
32
+ Lore.logger.debug { 'atomic update query' }
33
+ Lore.logger.debug { '----- ' << table.to_s + ' ------' }
34
+ Lore.logger.debug { 'Values: ' << value_keys.inspect }
35
+ Lore.logger.debug { 'Fields: ' << attributes.inspect }
36
+ Lore.logger.debug { 'Required: ' << required.inspect }
37
+
38
+ query_string = "UPDATE #{table} SET "
39
+ set_string = String.new
40
+ key_counter = 0
41
+ value_keys.each_pair { |attribute_name, value|
42
+
43
+ internal_attribute_name = attribute_name.to_s[0..24].to_sym
44
+ if value.empty? then
45
+ value = value_keys["#{table}.#{internal_attribute_name}"].to_s
46
+ end
47
+
48
+ # Disallow setting an empty value for required fields
49
+ if !(required[attribute_name] && value.empty?) && !(value.nil?) then
50
+ if key_counter > 0 then
51
+ set_string += ', '
52
+ end
53
+ set_string << "#{attribute_name} = '#{value}'"
54
+ key_counter = 1
55
+ end
56
+ }
57
+ query_string << set_string
58
+
59
+ query_string << ' WHERE '
60
+
61
+ field_counter=0
62
+ primary_key_values.each_pair { |field, value|
63
+ query_string << "#{field} = '#{value}'"
64
+ if field_counter < primary_key_values.keys.length-1
65
+ query_string << ' AND '
66
+ end
67
+ field_counter += 1
68
+ }
69
+ query_string << "; "
70
+
71
+ return query_string
72
+ end # }}}
73
+
74
+ public
75
+
76
+ def block_update(&block)
77
+ # {{{
78
+ query_string = "UPDATE #{@base_table} "
79
+
80
+ if block_given? then
81
+ yield_obj = Lore::Clause_Parser.new(@accessor)
82
+ clause = yield *yield_obj
83
+ end
84
+
85
+ query_string += clause.set_part
86
+ query_string += clause.where_part
87
+
88
+ Lore::Context.enter(@accessor.get_context) if @accessor.get_context
89
+ begin
90
+ Lore::Connection.perform(query_string)
91
+ ensure
92
+ Lore::Context.leave if @accessor.get_context
93
+ end
94
+
95
+ end # }}}
96
+
97
+ def update_query(accessor,
98
+ primary_key_values,
99
+ value_keys,
100
+ query_string='')
101
+ # {{{
102
+ Lore.logger.debug { 'Update query: ' }
103
+ Lore.logger.debug { value_keys.inspect }
104
+ Lore.logger.debug { primary_key_values.inspect }
105
+
106
+ associations = accessor.__associations__
107
+ is_a_hierarchy = associations.base_klasses_tree()
108
+ joined_models = associations.base_klasses()
109
+ is_a_hierarchy.each_pair { |table, base_tables|
110
+
111
+ # pass base tables first, recursively, as IS_A-based creation has
112
+ # to be done bottom-up:
113
+ Lore.logger.debug { 'For ' << table.to_s }
114
+ Lore.logger.debug { joined_models.inspect }
115
+ query_string << update_query(joined_models[table].first,
116
+ primary_key_values,
117
+ value_keys
118
+ ).to_s
119
+ }
120
+ # finally, add query string for this table:
121
+ table_name = accessor.table_name
122
+ query_string << atomic_update_query(accessor,
123
+ primary_key_values[table_name],
124
+ value_keys[table_name]
125
+ ).to_s
126
+
127
+ query_string
128
+
129
+ end # }}}
130
+
131
+ public
132
+
133
+ def perform_update(accessor_instance)
134
+ # {{{
135
+ query_string = update_query(@accessor,
136
+ accessor_instance.update_pkey_values,
137
+ # accessor_instance.get_attribute_value_map)
138
+ accessor_instance.update_values)
139
+
140
+ Lore::Context.enter(@accessor.get_context) if @accessor.get_context
141
+ begin
142
+ Lore::Connection.perform("BEGIN;\n#{query_string}\nCOMMIT;")
143
+ rescue ::Exception => excep
144
+ Lore::Connection.perform("ROLLBACK;")
145
+ raise excep
146
+ ensure
147
+ Lore::Context.leave if @accessor.get_context
148
+ end
149
+ @accessor.flush_entity_cache()
150
+
151
+ end # }}}
152
+
153
+ end # class
154
+
155
+ end # module
@@ -1,11 +1,12 @@
1
1
 
2
2
  require('lore/validation/type_validator')
3
- require('lore/exception/invalid_parameter')
3
+ require('lore/exceptions/invalid_field')
4
+ require('lore/exceptions/validation_failure')
4
5
 
5
6
  module Lore
6
7
  module Validation
7
8
 
8
- class Parameter_Validator # :nodoc:
9
+ class Parameter_Validator
9
10
 
10
11
  PG_BOOL = 16
11
12
  PG_SMALLINT = 21
@@ -22,56 +23,109 @@ module Validation
22
23
  # or e.g. in a dispatcher with
23
24
  # Validator.invalid_params(Some_Klass, parameter_hash)
24
25
  #
25
- def self.invalid_params(klass, value_hash)
26
+ def self.validate(klass, value_hash)
26
27
 
27
- invalid_params = Hash.new
28
- explicit_attributes = klass.get_explicit_attributes
29
- constraints = klass.get_constraints
28
+ Lore.logger.debug { "Validating attributes for #{klass.to_s}: " }
29
+ Lore.logger.debug { "#{value_hash.inspect}" }
30
+ invalid_params = Hash.new
31
+ attribute_settings = klass.__attributes__
32
+ constraints = attribute_settings.constraints
33
+ required = attribute_settings.required
30
34
 
31
- klass.get_attribute_types.each_pair { |table, fields|
35
+ attribute_settings.types.each_pair { |table, fields|
32
36
  begin
33
- validate_types(fields, value_hash[table], explicit_attributes[table])
34
- rescue Exception::Invalid_Types => ip
37
+ validate_types(fields, value_hash[table], required[table])
38
+ rescue Lore::Exceptions::Invalid_Types => ip
35
39
  invalid_params[table] = ip
36
40
  end
37
41
  }
38
42
 
39
- klass.get_constraints.each_pair { |table, fields|
43
+ attribute_settings.constraints.each_pair { |table, fields|
40
44
  begin
41
45
  validate_constraints(fields, value_hash[table])
42
- rescue Exception::Unmet_Constraints => ip
46
+ rescue Lore::Exceptions::Unmet_Constraints => ip
43
47
  invalid_params[table] = ip
44
48
  end
45
49
  }
46
50
  if invalid_params.length == 0 then return true end
47
51
 
48
- raise Lore::Exception::Invalid_Klass_Parameters.new(klass, invalid_params)
52
+ raise Lore::Exceptions::Validation_Failure.new(klass, invalid_params)
49
53
 
50
54
  end
51
55
 
52
- def self.validate_types(type_codes, table_value_hash, table_explicit_attributes)
53
- invalid_types = {}
54
- value = false
55
- type_validator = Type_Validator.new()
56
- type_codes.each_pair { |field, type|
56
+ def self.validate_update(klass, value_hash)
57
+ Lore.logger.debug { "Validating attributes for updating #{klass.to_s}: " }
58
+ Lore.logger.debug { "#{value_hash.inspect}" }
59
+ invalid_params = Hash.new
60
+ attribute_settings = klass.__attributes__
61
+ constraints = attribute_settings.constraints
62
+ required = attribute_settings.required
63
+
64
+ value_hash.each_pair { |table, attributes|
65
+ types = attribute_settings.types[table]
66
+ if !types then
67
+ raise ::Exception.new("No types given for #{klass.to_s} (#{table})")
68
+ end
69
+ types.delete_if { |attribute,value| !attributes[attribute] }
70
+ begin
71
+ validate_types(types, attributes, required[table])
72
+ rescue Lore::Exceptions::Invalid_Types => ip
73
+ invalid_params[table] = ip
74
+ end
75
+ }
76
+
77
+ value_hash.each_pair { |table, attributes|
78
+ constraints = attribute_settings.constraints[table]
79
+ if constraints then
80
+ constraints.delete_if { |attribute,constraint| !attributes[attribute] }
81
+ begin
82
+ validate_constraints(constraints, attributes)
83
+ rescue Lore::Exceptions::Unmet_Constraints => ip
84
+ invalid_params[table] = ip
85
+ end
86
+ else
87
+ Lore.logger.info { "No constraints for #{klass.to_s}?" }
88
+ end
89
+ }
90
+ if invalid_params.length == 0 then return true end
57
91
 
58
- nil_allowed = table_explicit_attributes.nil? ||
59
- !table_explicit_attributes.include?(field)
92
+ raise Lore::Exceptions::Validation_Failure.new(klass, invalid_params)
93
+
94
+ end
60
95
 
61
- value = table_value_hash[field]
96
+ def self.validate_types(type_codes, table_value_hash, required)
97
+ invalid_types = {}
98
+ value = false
99
+ type_validator = Type_Validator.new()
100
+
101
+ # DERRN-DERRN-DERRN!! What if there is no value hash?
102
+ type_codes.each_pair { |field,type|
103
+ field = field.to_sym
104
+ is_required = (required && required[field]) || false
105
+
106
+ value = table_value_hash[field] if table_value_hash
62
107
  # Replace whitespaces and array delimiters to check for real value length
63
108
  value_nil = (value.nil? || value.to_s.gsub(/\s/,'').gsub(/[{}]/,'').length == 0)
109
+ Lore.logger.debug {
110
+ "Validate #{field}, required? #{is_required}, " <<
111
+ "value: #{value.inspect}, value nil? #{value_nil}"
112
+ }
64
113
  # Is value missing?
65
- if (!nil_allowed && value_nil) then
114
+ if (is_required && value_nil) then
66
115
  invalid_types[field] = :missing
67
- # If so: Is value of valid type?
68
- elsif !type_validator.typecheck(type, value, nil_allowed) then
116
+ Lore.logger.debug { "Field #{field} is :missing" }
117
+ # Otherwise: Is value of valid type?
118
+ elsif !value_nil && !type_validator.typecheck(type, value, is_required) then
69
119
  invalid_types[field] = type
120
+ Lore.logger.debug {
121
+ "Field #{field} has invalid type: " <<
122
+ "expected: #{type}, value: #{value}"
123
+ }
70
124
  end
71
125
 
72
126
  }
73
127
  if invalid_types.keys.length > 0 then
74
- raise Lore::Exception::Invalid_Types.new(invalid_types)
128
+ raise Lore::Exceptions::Invalid_Types.new(invalid_types)
75
129
  end
76
130
  return true
77
131
  end
@@ -79,21 +133,26 @@ module Validation
79
133
  def self.validate_constraints(table_constraints, table_value_hash)
80
134
  unmet_constraints = {}
81
135
  table_constraints.each_pair { |attrib, rules|
82
- value = table_value_hash[attrib.to_s]
136
+ value = table_value_hash[attrib.to_s] if table_value_hash
83
137
  rules.each_pair { |rule, rule_value|
138
+ Lore.logger.debug { "Found constraint for #{attrib}: #{rule.inspect} " }
139
+ Lore.logger.debug { "Rule is: #{rule_value.inspect} " }
84
140
  if rule == :minlength && value.to_s.length < rule_value then
85
141
  unmet_constraints[attrib] = :minlength
142
+ Lore.logger.debug { "Field #{attrib} failed :minlength" }
86
143
  end
87
144
  if rule == :maxlength && value.to_s.length > rule_value then
88
145
  unmet_constraints[attrib] = :maxlength
146
+ Lore.logger.debug { "Field #{attrib} failed :maxlength" }
89
147
  end
90
148
  if rule == :format && rule_value.match(value).nil? then
91
149
  unmet_constraints[attrib] = :format
150
+ Lore.logger.debug { "Field #{attrib} failed :format" }
92
151
  end
93
152
  }
94
153
  }
95
154
  if unmet_constraints.length > 0 then
96
- raise Lore::Exception::Unmet_Constraints.new(unmet_constraints)
155
+ raise Lore::Exceptions::Unmet_Constraints.new(unmet_constraints)
97
156
  end
98
157
  return true
99
158
  end
@@ -1,88 +1,44 @@
1
1
 
2
- require('lore/exception/invalid_parameter')
3
- require('lore/exception/unknown_typecode')
4
- require('lore/types')
2
+ require('lore/exceptions/invalid_field')
3
+ require('lore/exceptions/unknown_type')
4
+ require('lore/adapters/postgres')
5
5
 
6
6
  module Lore
7
7
  module Validation
8
8
 
9
9
  class Type_Validator # :nodoc:
10
10
 
11
- def typecheck(code, value, nil_allowed=true)
12
-
13
- case code
14
-
15
- # bool
16
- when Lore::PG_BOOL
17
- if value == 't' || value == 'f' ||
18
- value == '' && nil_allowed || value.nil? && nil_allowed
19
- then true else false end
20
- # bytea
21
- when Lore::PG_BYTEA
22
- true
23
- # int
24
- when Lore::PG_INT
25
- if value.kind_of?(Integer) or
26
- value.to_i.to_s == value or
27
- value.nil? && nil_allowed or
28
- value == '' && nil_allowed
29
- then true else false end
30
- # smallint
31
- when Lore::PG_SMALLINT
32
- if ((value.kind_of?(Integer) or value.to_i.to_s == value or
33
- value.nil? && nil_allowed || value == '' && nil_allowed)) and
34
- value.to_i < 1024 and value.to_i > -1024
35
- then true else false end
36
- # decimal
37
- when Lore::PG_DECIMAL
38
- if ((value.kind_of?(Integer) or value.to_f.to_s == value or
39
- value.nil? && nil_allowed || value == '' && nil_allowed))
40
- then true else false end
41
- # text
42
- when Lore::PG_TEXT
43
- if nil_allowed || !nil_allowed && !value.nil? && value != ''
44
- then true else false end
45
- # varchar
46
- when Lore::PG_CHAR
47
- if nil_allowed || !nil_allowed && !value.nil? && value != ''
48
- then true else false end
49
- # varchar
50
- when Lore::PG_CHARACTER
51
- if nil_allowed || !nil_allowed && !value.nil? && value != ''
52
- then true else false end
53
- # varchar
54
- when Lore::PG_VARCHAR
55
- if nil_allowed || !nil_allowed && !value.nil? && value != ''
56
- then true else false end
57
- # timestamp
58
- when Lore::PG_TIME
59
- # TODO
60
- if nil_allowed || !nil_allowed && !value.nil? && value != ''
61
- then true else false end
62
- # timestamp with timezone
63
- when Lore::PG_TIMESTAMP
64
- # TODO
65
- if nil_allowed || !nil_allowed && !value.nil? && value != ''
66
- then true else false end
67
- # timestamp with timezone
68
- when Lore::PG_TIMESTAMP_TIMEZONE
69
- # TODO
70
- if nil_allowed || !nil_allowed && !value.nil? && value != ''
71
- then true else false end
72
- # date
73
- when Lore::PG_DATE
74
- # TODO
75
- if nil_allowed || !nil_allowed && !value.nil? && value != ''
76
- then true else false end
77
-
78
- # character varying[]
79
- when Lore::PG_VCHAR_LIST
80
- true
81
-
82
- else
83
- raise ::Exception.new('Unknown type code (' << code.inspect + ') for value ' << value.inspect + '. See README on how to add new types. ')
84
- end
85
-
11
+ @@type_validation_rules = {
12
+ Lore::PG_BOOL => Proc.new { |value, required|
13
+ (value == 't' || value == 'f' || value.empty? && !required)
14
+ },
15
+ Lore::PG_BYTEA => Proc.new { |value, required| true },
16
+ Lore::PG_INT => Proc.new { |value, required|
17
+ value && ((value.kind_of?(Integer) || value.to_i.to_s == value)) ||
18
+ !required && (value.empty?)
19
+ },
20
+ Lore::PG_SMALLINT => Proc.new { |value, required|
21
+ value && ((value.kind_of?(Integer) || value.to_i.to_s == value) &&
22
+ (value.to_i < 1024 && value.to_i > -1024)) ||
23
+ !required && (value.empty?)
24
+ },
25
+ Lore::PG_DECIMAL => Proc.new { |value, required|
26
+ value && (value.kind_of?(Integer) || value.to_f.to_s == value) ||
27
+ !required && (value.empty?)
28
+ },
29
+ Lore::PG_TEXT => Proc.new { |value, required| !required || !value.empty? },
30
+ Lore::PG_VARCHAR => Proc.new { |value, required| !required || !value.empty? },
31
+ Lore::PG_TIME => Proc.new { |value, required| !required || !value.empty? }, # TODO
32
+ Lore::PG_DATE => Proc.new { |value, required| !required || !value.empty? }, # TODO
33
+ Lore::PG_TIMESTAMP => Proc.new { |value, required| !required || !value.empty? }, # TODO
34
+ Lore::PG_VCHAR_LIST => Proc.new { |value, required| !required || !value.empty? }, # TODO
35
+ Lore::PG_TIMESTAMP_TIMEZONE => Proc.new { |value, required| !required || !value.empty? } # TODO
36
+ }
37
+
38
+ def typecheck(code, value, is_required)
39
+ validation = @@type_validation_rules[code]
40
+ return validation.call(value, is_required) if validation
41
+ raise Lore::Exceptions::Unkown_Type.new(code, value)
86
42
  end
87
43
 
88
44
  end