finitio 0.4.1 → 0.5.0

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 (270) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +66 -0
  3. data/Gemfile +1 -1
  4. data/Gemfile.lock +34 -30
  5. data/finitio.gemspec +1 -1
  6. data/lib/finitio.rb +7 -39
  7. data/lib/finitio/errors.rb +14 -0
  8. data/lib/finitio/support.rb +4 -1
  9. data/lib/finitio/support/attribute.rb +13 -7
  10. data/lib/finitio/support/compilation.rb +55 -0
  11. data/lib/finitio/support/constraint.rb +46 -0
  12. data/lib/finitio/support/contract.rb +33 -0
  13. data/lib/finitio/support/dress_helper.rb +3 -2
  14. data/lib/finitio/support/heading.rb +57 -17
  15. data/lib/finitio/support/metadata.rb +20 -0
  16. data/lib/finitio/support/type_factory.rb +154 -41
  17. data/lib/finitio/syntax.rb +16 -31
  18. data/lib/finitio/syntax/expr.rb +56 -0
  19. data/lib/finitio/syntax/expr/arith_op.rb +22 -0
  20. data/lib/finitio/syntax/expr/comparison.rb +22 -0
  21. data/lib/finitio/syntax/expr/fn_call.rb +24 -0
  22. data/lib/finitio/syntax/expr/identifier.rb +18 -0
  23. data/lib/finitio/syntax/expr/literal.rb +19 -0
  24. data/lib/finitio/syntax/expr/logic_dyadic.rb +22 -0
  25. data/lib/finitio/syntax/expr/logic_not.rb +21 -0
  26. data/lib/finitio/syntax/expr/oo_call.rb +24 -0
  27. data/lib/finitio/syntax/expr/parenthesized.rb +20 -0
  28. data/lib/finitio/syntax/expr/unary_minus_op.rb +21 -0
  29. data/lib/finitio/syntax/expressions.citrus +129 -0
  30. data/lib/finitio/syntax/finitio.citrus +10 -208
  31. data/lib/finitio/syntax/finitio.sexp +5 -1
  32. data/lib/finitio/syntax/lexer.citrus +91 -0
  33. data/lib/finitio/syntax/literal.rb +16 -0
  34. data/lib/finitio/syntax/literal/boolean.rb +22 -0
  35. data/lib/finitio/syntax/literal/integer.rb +14 -0
  36. data/lib/finitio/syntax/literal/real.rb +14 -0
  37. data/lib/finitio/syntax/literal/string.rb +14 -0
  38. data/lib/finitio/syntax/literals.citrus +44 -0
  39. data/lib/finitio/syntax/node.rb +53 -0
  40. data/lib/finitio/syntax/type.rb +28 -0
  41. data/lib/finitio/syntax/type/ad_type.rb +29 -0
  42. data/lib/finitio/syntax/{any_type.rb → type/any_type.rb} +1 -1
  43. data/lib/finitio/syntax/type/attribute.rb +33 -0
  44. data/lib/finitio/syntax/{builtin_type.rb → type/builtin_type.rb} +3 -1
  45. data/lib/finitio/syntax/{constraint_def.rb → type/constraint_def.rb} +4 -3
  46. data/lib/finitio/syntax/type/constraints.rb +17 -0
  47. data/lib/finitio/syntax/{contract.rb → type/contract.rb} +9 -3
  48. data/lib/finitio/syntax/{definitions.rb → type/definitions.rb} +1 -0
  49. data/lib/finitio/syntax/{expression.rb → type/expression.rb} +2 -1
  50. data/lib/finitio/syntax/{external_pair.rb → type/external_pair.rb} +3 -1
  51. data/lib/finitio/syntax/type/heading.rb +30 -0
  52. data/lib/finitio/syntax/{inline_pair.rb → type/inline_pair.rb} +3 -1
  53. data/lib/finitio/syntax/{lambda_expr.rb → type/lambda_expr.rb} +3 -0
  54. data/lib/finitio/syntax/type/main_type.rb +18 -0
  55. data/lib/finitio/syntax/type/metadata.rb +18 -0
  56. data/lib/finitio/syntax/type/metadata_attr.rb +15 -0
  57. data/lib/finitio/syntax/{named_constraint.rb → type/named_constraint.rb} +10 -3
  58. data/lib/finitio/syntax/type/relation_type.rb +24 -0
  59. data/lib/finitio/syntax/{seq_type.rb → type/seq_type.rb} +3 -0
  60. data/lib/finitio/syntax/{set_type.rb → type/set_type.rb} +3 -0
  61. data/lib/finitio/syntax/type/struct_type.rb +17 -0
  62. data/lib/finitio/syntax/{sub_type.rb → type/sub_type.rb} +3 -0
  63. data/lib/finitio/syntax/{system.rb → type/system.rb} +5 -4
  64. data/lib/finitio/syntax/type/tuple_type.rb +24 -0
  65. data/lib/finitio/syntax/{type_def.rb → type/type_def.rb} +8 -3
  66. data/lib/finitio/syntax/{type_ref.rb → type/type_ref.rb} +4 -1
  67. data/lib/finitio/syntax/{union_type.rb → type/union_type.rb} +1 -0
  68. data/lib/finitio/syntax/{unnamed_constraint.rb → type/unnamed_constraint.rb} +7 -1
  69. data/lib/finitio/syntax/types.citrus +196 -0
  70. data/lib/finitio/system.rb +15 -15
  71. data/lib/finitio/type.rb +38 -6
  72. data/lib/finitio/type/ad_type.rb +41 -18
  73. data/lib/finitio/type/alias_type.rb +37 -0
  74. data/lib/finitio/type/any_type.rb +7 -3
  75. data/lib/finitio/type/builtin_type.rb +5 -4
  76. data/lib/finitio/{support → type}/collection_type.rb +3 -4
  77. data/lib/finitio/type/hash_based_type.rb +91 -0
  78. data/lib/finitio/type/heading_based_type.rb +28 -0
  79. data/lib/finitio/type/multi_relation_type.rb +34 -0
  80. data/lib/finitio/type/multi_tuple_type.rb +29 -0
  81. data/lib/finitio/type/proxy_type.rb +40 -0
  82. data/lib/finitio/type/rel_based_type.rb +42 -0
  83. data/lib/finitio/type/relation_type.rb +6 -47
  84. data/lib/finitio/type/seq_type.rb +4 -0
  85. data/lib/finitio/type/set_type.rb +4 -0
  86. data/lib/finitio/type/struct_type.rb +84 -0
  87. data/lib/finitio/type/sub_type.rb +25 -22
  88. data/lib/finitio/type/tuple_type.rb +6 -57
  89. data/lib/finitio/type/union_type.rb +12 -5
  90. data/lib/finitio/version.rb +2 -2
  91. data/spec/{unit/attribute → attribute}/test_equality.rb +8 -5
  92. data/spec/{unit/attribute → attribute}/test_fetch_on.rb +5 -5
  93. data/spec/attribute/test_initialize.rb +26 -0
  94. data/spec/attribute/test_optional.rb +18 -0
  95. data/spec/attribute/test_required.rb +18 -0
  96. data/spec/attribute/test_to_name.rb +20 -0
  97. data/spec/constraint/test_anonymous.rb +20 -0
  98. data/spec/constraint/test_equality.rb +39 -0
  99. data/spec/constraint/test_name.rb +20 -0
  100. data/spec/constraint/test_named.rb +20 -0
  101. data/spec/constraint/test_triple_equal.rb +13 -0
  102. data/spec/{unit/qrb/system.q → finitio/system.fio} +0 -0
  103. data/spec/{unit/qrb → finitio}/test_ast.rb +0 -0
  104. data/spec/finitio/test_parse.rb +23 -0
  105. data/spec/{unit/qrb/test_parse.rb → finitio/test_system.rb} +6 -6
  106. data/spec/heading/test_allow_extra.rb +24 -0
  107. data/spec/{unit/heading → heading}/test_each.rb +2 -2
  108. data/spec/heading/test_equality.rb +38 -0
  109. data/spec/heading/test_hash.rb +38 -0
  110. data/spec/heading/test_hash_get.rb +17 -0
  111. data/spec/{unit/heading → heading}/test_initialize.rb +2 -2
  112. data/spec/heading/test_multi.rb +57 -0
  113. data/spec/{unit/heading → heading}/test_size.rb +0 -0
  114. data/spec/heading/test_to_name.rb +58 -0
  115. data/spec/spec_helper.rb +17 -1
  116. data/spec/syntax/expr/test_free_variables.rb +46 -0
  117. data/spec/syntax/expr/test_to_proc_source.rb +43 -0
  118. data/spec/{unit/syntax → syntax}/nodes/test_ad_type.rb +26 -26
  119. data/spec/{unit/syntax → syntax}/nodes/test_any_type.rb +2 -2
  120. data/spec/syntax/nodes/test_attribute.rb +65 -0
  121. data/spec/{unit/syntax → syntax}/nodes/test_builtin_type.rb +5 -5
  122. data/spec/{unit/syntax → syntax}/nodes/test_comment.rb +1 -1
  123. data/spec/{unit/syntax → syntax}/nodes/test_constraint_def.rb +3 -8
  124. data/spec/{unit/syntax → syntax}/nodes/test_constraints.rb +21 -16
  125. data/spec/{unit/syntax → syntax}/nodes/test_contract.rb +28 -35
  126. data/spec/{unit/syntax → syntax}/nodes/test_expression.rb +13 -5
  127. data/spec/{unit/syntax → syntax}/nodes/test_heading.rb +25 -7
  128. data/spec/syntax/nodes/test_metadata.rb +28 -0
  129. data/spec/{unit/syntax → syntax}/nodes/test_named_constraint.rb +8 -8
  130. data/spec/syntax/nodes/test_relation_type.rb +84 -0
  131. data/spec/{unit/syntax → syntax}/nodes/test_seq_type.rb +4 -4
  132. data/spec/{unit/syntax → syntax}/nodes/test_set_type.rb +4 -4
  133. data/spec/{unit/syntax → syntax}/nodes/test_spacing.rb +1 -1
  134. data/spec/syntax/nodes/test_struct_type.rb +38 -0
  135. data/spec/{unit/syntax → syntax}/nodes/test_sub_type.rb +14 -14
  136. data/spec/{unit/syntax → syntax}/nodes/test_system.rb +3 -3
  137. data/spec/syntax/nodes/test_tuple_type.rb +94 -0
  138. data/spec/syntax/nodes/test_type_def.rb +57 -0
  139. data/spec/{unit/syntax → syntax}/nodes/test_type_ref.rb +3 -3
  140. data/spec/{unit/syntax → syntax}/nodes/test_union_type.rb +3 -3
  141. data/spec/{unit/syntax → syntax}/nodes/test_unnamed_constraint.rb +7 -7
  142. data/spec/syntax/test_compile.rb +41 -0
  143. data/spec/{unit/syntax → syntax}/test_compile_type.rb +1 -1
  144. data/spec/{unit/system → system}/test_add_type.rb +6 -6
  145. data/spec/{unit/system → system}/test_dsl.rb +2 -2
  146. data/spec/{unit/system → system}/test_dup.rb +4 -4
  147. data/spec/{unit/system → system}/test_fetch.rb +4 -4
  148. data/spec/{unit/system → system}/test_get_type.rb +2 -2
  149. data/spec/{unit/system → system}/test_initialize.rb +0 -0
  150. data/spec/test_finitio.rb +8 -0
  151. data/spec/{unit/type → type}/ad_type/test_default_name.rb +1 -2
  152. data/spec/{unit/type → type}/ad_type/test_dress.rb +19 -9
  153. data/spec/{unit/type → type}/ad_type/test_include.rb +3 -3
  154. data/spec/{unit/type → type}/ad_type/test_initialize.rb +15 -8
  155. data/spec/{unit/type → type}/ad_type/test_name.rb +2 -2
  156. data/spec/type/alias_type/test_default_name.rb +10 -0
  157. data/spec/type/alias_type/test_delegation.rb +29 -0
  158. data/spec/type/alias_type/test_name.rb +10 -0
  159. data/spec/{unit/type → type}/any_type/test_default_name.rb +1 -1
  160. data/spec/{unit/type → type}/any_type/test_dress.rb +0 -0
  161. data/spec/{unit/type → type}/any_type/test_equality.rb +4 -4
  162. data/spec/{unit/type → type}/any_type/test_include.rb +2 -2
  163. data/spec/{unit/type → type}/any_type/test_initialize.rb +0 -0
  164. data/spec/{unit/type → type}/any_type/test_name.rb +2 -2
  165. data/spec/{unit/type → type}/builtin_type/test_default_name.rb +1 -1
  166. data/spec/{unit/type → type}/builtin_type/test_dress.rb +3 -3
  167. data/spec/{unit/type → type}/builtin_type/test_equality.rb +4 -4
  168. data/spec/{unit/type → type}/builtin_type/test_include.rb +2 -2
  169. data/spec/{unit/type → type}/builtin_type/test_initialize.rb +1 -1
  170. data/spec/{unit/type → type}/builtin_type/test_name.rb +2 -2
  171. data/spec/type/multi_relation_type/test_default_name.rb +19 -0
  172. data/spec/type/multi_relation_type/test_dress.rb +206 -0
  173. data/spec/type/multi_relation_type/test_equality.rb +36 -0
  174. data/spec/type/multi_relation_type/test_include.rb +89 -0
  175. data/spec/type/multi_relation_type/test_initialize.rb +29 -0
  176. data/spec/type/multi_relation_type/test_name.rb +27 -0
  177. data/spec/type/multi_tuple_type/test_default_name.rb +17 -0
  178. data/spec/type/multi_tuple_type/test_dress.rb +146 -0
  179. data/spec/type/multi_tuple_type/test_equality.rb +32 -0
  180. data/spec/type/multi_tuple_type/test_include.rb +73 -0
  181. data/spec/type/multi_tuple_type/test_initialize.rb +30 -0
  182. data/spec/type/multi_tuple_type/test_name.rb +24 -0
  183. data/spec/type/proxy_type/test_delegation.rb +37 -0
  184. data/spec/type/proxy_type/test_resolve.rb +29 -0
  185. data/spec/{unit/type → type}/relation_type/test_default_name.rb +0 -0
  186. data/spec/{unit/type → type}/relation_type/test_dress.rb +24 -24
  187. data/spec/{unit/type → type}/relation_type/test_equality.rb +6 -6
  188. data/spec/{unit/type → type}/relation_type/test_include.rb +4 -4
  189. data/spec/{unit/type → type}/relation_type/test_initialize.rb +2 -2
  190. data/spec/{unit/type → type}/relation_type/test_name.rb +0 -0
  191. data/spec/{unit/type → type}/seq_type/test_default_name.rb +0 -0
  192. data/spec/{unit/type → type}/seq_type/test_dress.rb +5 -5
  193. data/spec/{unit/type → type}/seq_type/test_equality.rb +4 -4
  194. data/spec/{unit/type → type}/seq_type/test_include.rb +4 -4
  195. data/spec/{unit/type → type}/seq_type/test_initialize.rb +3 -3
  196. data/spec/{unit/type → type}/seq_type/test_name.rb +0 -0
  197. data/spec/{unit/type → type}/set_type/test_default_name.rb +0 -0
  198. data/spec/{unit/type → type}/set_type/test_dress.rb +8 -8
  199. data/spec/{unit/type → type}/set_type/test_equality.rb +4 -4
  200. data/spec/{unit/type → type}/set_type/test_include.rb +4 -4
  201. data/spec/{unit/type → type}/set_type/test_initialize.rb +3 -3
  202. data/spec/{unit/type → type}/set_type/test_name.rb +0 -0
  203. data/spec/type/struct_type/test_default_name.rb +10 -0
  204. data/spec/type/struct_type/test_dress.rb +105 -0
  205. data/spec/type/struct_type/test_equality.rb +28 -0
  206. data/spec/type/struct_type/test_include.rb +40 -0
  207. data/spec/type/struct_type/test_initialize.rb +22 -0
  208. data/spec/type/struct_type/test_name.rb +20 -0
  209. data/spec/{unit/type → type}/sub_type/test_default_name.rb +2 -2
  210. data/spec/{unit/type → type}/sub_type/test_dress.rb +14 -14
  211. data/spec/type/sub_type/test_equality.rb +46 -0
  212. data/spec/{unit/type → type}/sub_type/test_include.rb +6 -6
  213. data/spec/type/sub_type/test_initialize.rb +13 -0
  214. data/spec/{unit/type → type}/sub_type/test_name.rb +4 -4
  215. data/spec/{unit/type → type}/tuple_type/test_default_name.rb +0 -0
  216. data/spec/{unit/type → type}/tuple_type/test_dress.rb +18 -18
  217. data/spec/{unit/type → type}/tuple_type/test_equality.rb +6 -6
  218. data/spec/{unit/type → type}/tuple_type/test_include.rb +4 -4
  219. data/spec/{unit/type → type}/tuple_type/test_initialize.rb +4 -4
  220. data/spec/{unit/type → type}/tuple_type/test_name.rb +0 -0
  221. data/spec/{unit/type → type}/union_type/test_default_name.rb +0 -0
  222. data/spec/{unit/type → type}/union_type/test_dress.rb +7 -6
  223. data/spec/{unit/type → type}/union_type/test_equality.rb +7 -7
  224. data/spec/{unit/type → type}/union_type/test_include.rb +3 -3
  225. data/spec/{unit/type → type}/union_type/test_initialize.rb +3 -3
  226. data/spec/{unit/type → type}/union_type/test_name.rb +0 -0
  227. data/spec/{unit/type_factory → type_factory}/dsl/test_adt.rb +4 -4
  228. data/spec/{unit/type_factory → type_factory}/dsl/test_any.rb +1 -1
  229. data/spec/{unit/type_factory → type_factory}/dsl/test_attribute.rb +16 -2
  230. data/spec/{unit/type_factory → type_factory}/dsl/test_attributes.rb +1 -1
  231. data/spec/{unit/type_factory → type_factory}/dsl/test_builtin.rb +3 -3
  232. data/spec/type_factory/dsl/test_multi_relation.rb +39 -0
  233. data/spec/type_factory/dsl/test_multi_tuple.rb +37 -0
  234. data/spec/{unit/type_factory → type_factory}/dsl/test_relation.rb +6 -6
  235. data/spec/{unit/type_factory → type_factory}/dsl/test_seq.rb +4 -4
  236. data/spec/{unit/type_factory → type_factory}/dsl/test_set.rb +4 -4
  237. data/spec/type_factory/dsl/test_struct.rb +45 -0
  238. data/spec/{unit/type_factory → type_factory}/dsl/test_subtype.rb +10 -8
  239. data/spec/{unit/type_factory → type_factory}/dsl/test_tuple.rb +5 -5
  240. data/spec/{unit/type_factory → type_factory}/dsl/test_union.rb +6 -6
  241. data/spec/{unit/type_factory → type_factory}/factory/test_builtin.rb +1 -1
  242. data/spec/{unit/type_factory → type_factory}/factory/test_seq_type.rb +2 -2
  243. data/spec/{unit/type_factory → type_factory}/factory/test_set_type.rb +2 -2
  244. data/spec/type_factory/factory/test_struct_type.rb +18 -0
  245. data/spec/{unit/type_factory → type_factory}/factory/test_sub_type.rb +7 -7
  246. data/spec/{unit/type_factory → type_factory}/factory/test_tuple_type.rb +4 -4
  247. metadata +398 -286
  248. data/lib/finitio/data_type.rb +0 -29
  249. data/lib/finitio/syntax/ad_type.rb +0 -32
  250. data/lib/finitio/syntax/attribute.rb +0 -15
  251. data/lib/finitio/syntax/constraints.rb +0 -22
  252. data/lib/finitio/syntax/heading.rb +0 -19
  253. data/lib/finitio/syntax/relation_type.rb +0 -15
  254. data/lib/finitio/syntax/support.rb +0 -13
  255. data/lib/finitio/syntax/tuple_type.rb +0 -15
  256. data/spec/acceptance/Finitio/test_default.rb +0 -96
  257. data/spec/acceptance/Finitio/test_parsing.rb +0 -15
  258. data/spec/acceptance/ad_type/test_in_finitio.rb +0 -82
  259. data/spec/acceptance/ad_type/test_in_ruby.rb +0 -60
  260. data/spec/unit/attribute/test_initialize.rb +0 -13
  261. data/spec/unit/attribute/test_to_name.rb +0 -10
  262. data/spec/unit/heading/test_equality.rb +0 -28
  263. data/spec/unit/heading/test_to_name.rb +0 -32
  264. data/spec/unit/syntax/nodes/test_attribute.rb +0 -38
  265. data/spec/unit/syntax/nodes/test_relation_type.rb +0 -59
  266. data/spec/unit/syntax/nodes/test_tuple_type.rb +0 -59
  267. data/spec/unit/syntax/nodes/test_type_def.rb +0 -33
  268. data/spec/unit/test_finitio.rb +0 -15
  269. data/spec/unit/type/sub_type/test_equality.rb +0 -34
  270. data/spec/unit/type/sub_type/test_initialize.rb +0 -16
@@ -48,29 +48,36 @@ module Finitio
48
48
  #
49
49
  class AdType < Type
50
50
 
51
- def initialize(ruby_type, contracts, name = nil)
51
+ def initialize(ruby_type, contracts, name = nil, metadata = nil)
52
52
  unless ruby_type.nil? or ruby_type.is_a?(Module)
53
53
  raise ArgumentError, "Module expected, got `#{ruby_type}`"
54
54
  end
55
- unless contracts.is_a?(Hash)
56
- raise ArgumentError, "Hash expected, got `#{contracts}`"
57
- end
58
- invalid = contracts.values.reject{|v|
59
- v.is_a?(Array) and v.size == 3 and v[0].is_a?(Type) and \
60
- v[1].respond_to?(:call) and v[2].respond_to?(:call)
61
- }
62
- unless invalid.empty?
63
- raise ArgumentError, "Invalid contracts `#{invalid}`"
55
+ unless contracts.is_a?(Array) &&
56
+ contracts.all?{|c| c.is_a?(Contract) }
57
+ raise ArgumentError, "[Contract] expected, got `#{contracts}`"
64
58
  end
65
59
 
66
- super(name)
60
+ super(name, metadata)
67
61
  @ruby_type = ruby_type
68
62
  @contracts = contracts.freeze
69
63
  end
70
64
  attr_reader :ruby_type, :contracts
71
65
 
66
+ alias :representator :ruby_type
67
+
68
+ def ruby_type=(ruby_type)
69
+ @ruby_type = ruby_type
70
+ @contracts.each do |contract|
71
+ contract.bind_ruby_type(ruby_type)
72
+ end
73
+ end
74
+
75
+ def [](name)
76
+ contracts.find{|c| c.name == name }
77
+ end
78
+
72
79
  def contract_names
73
- contracts.keys
80
+ contracts.map(&:name)
74
81
  end
75
82
 
76
83
  def default_name
@@ -85,27 +92,43 @@ module Finitio
85
92
  # Up should be idempotent with respect to the ADT
86
93
  return value if ruby_type and value.is_a?(ruby_type)
87
94
 
95
+ # Dressed value and first exception
96
+ dressed, error = nil, nil
97
+
88
98
  # Try each contract in turn. Do nothing on TypeError as
89
99
  # the next candidate could be the good one! Return the
90
100
  # first successfully dressed.
91
- contracts.each_pair do |name, (infotype, dresser, _)|
101
+ contracts.each do |contract|
92
102
 
93
103
  # First make the dress transformation on the information type
94
104
  success, dressed = handler.just_try do
95
- infotype.dress(value, handler)
105
+ contract.infotype.dress(value, handler)
106
+ end
107
+
108
+ # Save very first error on failure
109
+ unless success
110
+ error ||= dressed
111
+ next
96
112
  end
97
- next unless success
98
113
 
99
114
  # Seems nice, just try to get one stage higher now
100
115
  success, dressed = handler.just_try(StandardError) do
101
- dresser.call(dressed)
116
+ contract.dresser.call(dressed)
102
117
  end
103
- return dressed if success
104
118
 
119
+ if success
120
+ if ruby_type && !dressed.is_a?(ruby_type)
121
+ raise "Invalid IC dresser (#{contract.dresser}):"\
122
+ " #{ruby_type} expected, got #{dressed.class}"
123
+ end
124
+ return dressed
125
+ else
126
+ error ||= dressed
127
+ end
105
128
  end
106
129
 
107
130
  # No one succeeded, just fail
108
- handler.failed!(self, value)
131
+ handler.failed!(self, value, error)
109
132
  end
110
133
 
111
134
  end # class AdType
@@ -0,0 +1,37 @@
1
+ module Finitio
2
+ class AliasType < Type
3
+
4
+ def initialize(target, name, metadata = nil)
5
+ unless target.is_a?(Type)
6
+ raise ArgumentError, "Type expected for target type, got `#{target}`"
7
+ end
8
+ if name.nil?
9
+ raise ArgumentError, "Alias name cannot be nil"
10
+ end
11
+
12
+ super(name, metadata)
13
+ @target = target
14
+ end
15
+ attr_reader :target
16
+
17
+ def default_name
18
+ @name
19
+ end
20
+
21
+ [
22
+ :representator,
23
+ :dress,
24
+ :undress,
25
+ :include?,
26
+ :==,
27
+ :eql?,
28
+ :hash,
29
+ :to_s
30
+ ].each do |meth|
31
+ define_method(meth) do |*args, &bl|
32
+ @target.send(meth, *args, &bl)
33
+ end
34
+ end
35
+
36
+ end # class AliasType
37
+ end # module Finitio
@@ -18,14 +18,18 @@ module Finitio
18
18
  #
19
19
  class AnyType < Type
20
20
 
21
- def initialize(name = nil)
22
- super(name)
21
+ def initialize(name = nil, metadata = nil)
22
+ super(name, metadata)
23
23
  end
24
24
 
25
25
  def default_name
26
26
  "Any"
27
27
  end
28
28
 
29
+ def representator
30
+ Object
31
+ end
32
+
29
33
  def include?(value)
30
34
  true
31
35
  end
@@ -35,7 +39,7 @@ module Finitio
35
39
  end
36
40
 
37
41
  def ==(other)
38
- other.is_a?(AnyType)
42
+ super || other.is_a?(AnyType)
39
43
  end
40
44
  alias :eql? :==
41
45
 
@@ -21,12 +21,14 @@ module Finitio
21
21
  #
22
22
  class BuiltinType < Type
23
23
 
24
- def initialize(ruby_type, name = nil)
25
- super(name)
24
+ def initialize(ruby_type, name = nil, metadata = nil)
25
+ super(name, metadata)
26
26
  @ruby_type = ruby_type
27
27
  end
28
28
  attr_reader :ruby_type
29
29
 
30
+ alias :representator :ruby_type
31
+
30
32
  def default_name
31
33
  @ruby_type.name.to_s
32
34
  end
@@ -43,8 +45,7 @@ module Finitio
43
45
  end
44
46
 
45
47
  def ==(other)
46
- return false unless other.is_a?(BuiltinType)
47
- other.ruby_type==ruby_type
48
+ super || (other.is_a?(BuiltinType) && other.ruby_type==ruby_type)
48
49
  end
49
50
  alias :eql? :==
50
51
 
@@ -1,19 +1,18 @@
1
1
  module Finitio
2
2
  module CollectionType
3
3
 
4
- def initialize(elm_type, name = nil)
4
+ def initialize(elm_type, name = nil, metadata = nil)
5
5
  unless elm_type.is_a?(Type)
6
6
  raise ArgumentError, "Finitio::Type expected, got `#{elm_type}`"
7
7
  end
8
8
 
9
- super(name)
9
+ super(name, metadata)
10
10
  @elm_type = elm_type
11
11
  end
12
12
  attr_reader :elm_type
13
13
 
14
14
  def ==(other)
15
- return false unless other.is_a?(self.class)
16
- elm_type == other.elm_type
15
+ super || (other.is_a?(self.class) && elm_type == other.elm_type)
17
16
  end
18
17
  alias :eql? :==
19
18
 
@@ -0,0 +1,91 @@
1
+ module Finitio
2
+ module HashBasedType
3
+
4
+ def representator
5
+ rep = {}
6
+ heading.each do |attr|
7
+ rep[attr.name] = rep[attr.type.representator]
8
+ end
9
+ rep
10
+ end
11
+
12
+ def include?(value)
13
+ value.is_a?(Hash) &&
14
+ valid_attrs?(value) &&
15
+ heading.all?{|a|
16
+ value.has_key?(a.name) ? a.type.include?(value[a.name]) : true
17
+ }
18
+ end
19
+
20
+ # Convert `value` (supposed to be Hash) to a Tuple, by checking attributes
21
+ # and applying `dress` on them in turn. Raise an error if any attribute
22
+ # is missing or unrecognized, as well as if any sub transformation fails.
23
+ def dress(value, handler = DressHelper.new)
24
+ handler.failed!(self, value) unless looks_a_tuple?(value)
25
+
26
+ # Check for extra attributes
27
+ unless heading.allow_extra? or (extra = extra_attrs(value, true)).empty?
28
+ handler.fail!("Unrecognized attribute `#{extra.first}`")
29
+ end
30
+
31
+ # Check for missing attributes
32
+ unless (missing = missing_attrs(value, true)).empty?
33
+ handler.fail!("Missing attribute `#{missing.first}`")
34
+ end
35
+
36
+ # Uped values, i.e. tuple under construction
37
+ uped = {}
38
+
39
+ # Up each attribute in turn now. Fail on missing ones.
40
+ heading.each do |attribute|
41
+ present = true
42
+ val = attribute.fetch_on(value){ present = false }
43
+ next unless present
44
+ handler.deeper(attribute.name) do
45
+ uped[attribute.name] = attribute.type.dress(val, handler)
46
+ end
47
+ end
48
+
49
+ uped
50
+ end
51
+
52
+ protected
53
+
54
+ def looks_a_tuple?(value)
55
+ value.is_a?(Hash) or value.respond_to?(:fetch)
56
+ end
57
+
58
+ def attr_names
59
+ @attr_names ||= heading.map(&:name)
60
+ end
61
+
62
+ def req_attr_names
63
+ @req_attr_names ||= heading.select(&:required).map(&:name)
64
+ end
65
+
66
+ def attrs(as, to_s)
67
+ to_s ? as.map(&:to_s) : as
68
+ end
69
+
70
+ def extra_attrs(value, to_s = false)
71
+ attrs(value.keys, to_s) - attrs(attr_names, to_s)
72
+ end
73
+
74
+ def extra_attr?(value, to_s = false)
75
+ !extra_attrs(value, to_s).empty?
76
+ end
77
+
78
+ def missing_attrs(value, to_s = false)
79
+ attrs(req_attr_names, to_s) - attrs(value.keys, to_s)
80
+ end
81
+
82
+ def missing_attr?(value, to_s = false)
83
+ !missing_attrs(value, to_s).empty?
84
+ end
85
+
86
+ def valid_attrs?(value, to_s = false)
87
+ (heading.allow_extra? || !extra_attr?(value, to_s)) && !missing_attr?(value)
88
+ end
89
+
90
+ end # module HashBasedType
91
+ end # module Finitio
@@ -0,0 +1,28 @@
1
+ module Finitio
2
+ module HeadingBasedType
3
+
4
+ def initialize(heading, name = nil, metadata = nil)
5
+ unless heading.is_a?(Heading)
6
+ raise ArgumentError, "Heading expected, got `#{heading}`"
7
+ end
8
+
9
+ super(name, metadata)
10
+ @heading = heading
11
+ end
12
+ attr_reader :heading
13
+
14
+ def [](attrname)
15
+ heading.fetch(attrname)
16
+ end
17
+
18
+ def ==(other)
19
+ super || (other.is_a?(self.class) && heading == other.heading)
20
+ end
21
+ alias :eql? :==
22
+
23
+ def hash
24
+ self.class.hash ^ heading.hash
25
+ end
26
+
27
+ end # module HeadingBasedType
28
+ end # module Finitio
@@ -0,0 +1,34 @@
1
+ module Finitio
2
+ #
3
+ # The MultiRelation type generator allows capturing sets of information
4
+ # facts, but allowing optional attributes. E. g.,
5
+ #
6
+ # ColoredPoints = {{ point: Point, color :? Color }}
7
+ #
8
+ # This class allows capturing those types, in a way similar to
9
+ # MultiTupleType:
10
+ #
11
+ # ColoredPoints = MultiRelationType.new( Heading[...] )
12
+ #
13
+ # A ruby Set is used as concrete representation, and will contain hashes
14
+ # that are valid representations of the associated multi tuple type:
15
+ #
16
+ # R(ColoredPoints) = Set[ R({...}) ] = Set[Hash[...]]
17
+ #
18
+ # Accordingly, the dress transformation function has the signature below.
19
+ # It expects an Enumerable as input and fails if any duplicate is found
20
+ # (after tuple transformation), or if any tuple fails at being transformed.
21
+ #
22
+ # dress :: Alpha -> ColoredPoints throws TypeError
23
+ # dress :: Object -> Set[Hash[...]] throws TypeError
24
+ #
25
+ class MultiRelationType < Type
26
+ include HeadingBasedType
27
+ include RelBasedType
28
+
29
+ def default_name
30
+ "{{#{heading.to_name}}}"
31
+ end
32
+
33
+ end # class MultiRelationType
34
+ end # module Finitio
@@ -0,0 +1,29 @@
1
+ module Finitio
2
+ #
3
+ # The MultiTuple type generator allows capturing information *facts* with
4
+ # optional attributes. For instance, a Point type with an optional color
5
+ # could be defined as follows:
6
+ #
7
+ # Point = { r: Length, theta: Angle, color :? Color }
8
+ #
9
+ # This class allows capturing those information types. Note that it is
10
+ # actually syntactic sugar over union types:
11
+ #
12
+ # Point = { r: Length, theta: Angle }
13
+ # | { r: Length, theta: Angle, color: Color }
14
+ #
15
+ # A Hash with Symbol as keys is used as concrete ruby representation for
16
+ # multi tuples. The values map to the concrete representations of each
17
+ # attribute type. The dress function is similar to the one of TupleType
18
+ # but allows optional attributes to be omitted
19
+ #
20
+ class MultiTupleType < Type
21
+ include HeadingBasedType
22
+ include HashBasedType
23
+
24
+ def default_name
25
+ "{#{heading.to_name}}"
26
+ end
27
+
28
+ end # class MultiTupleType
29
+ end # module Finitio
@@ -0,0 +1,40 @@
1
+ module Finitio
2
+ class ProxyType < Type
3
+
4
+ def initialize(target_name, target = nil)
5
+ unless target_name.is_a?(String)
6
+ raise ArgumentError, "String expected for type name, got `#{target_name}`"
7
+ end
8
+
9
+ @target_name = target_name
10
+ @target = target
11
+ end
12
+ attr_reader :target_name, :target
13
+
14
+ [
15
+ :representator,
16
+ :name,
17
+ :name=,
18
+ :default_name,
19
+ :dress,
20
+ :undress,
21
+ :include?,
22
+ :==,
23
+ :eql?,
24
+ :hash,
25
+ :to_s
26
+ ].each do |meth|
27
+ define_method(meth) do |*args, &bl|
28
+ raise Error, "Proxy not resolved" unless @target
29
+ @target.send(meth, *args, &bl)
30
+ end
31
+ end
32
+
33
+ def resolve(system)
34
+ @target = system.fetch(target_name) do
35
+ raise Error, "No such type `#{target_name}`"
36
+ end
37
+ end
38
+
39
+ end # class ProxyType
40
+ end # module Finitio
@@ -0,0 +1,42 @@
1
+ module Finitio
2
+ module RelBasedType
3
+
4
+ def representator
5
+ [tuple_type.representator]
6
+ end
7
+
8
+ def include?(value)
9
+ value.is_a?(Set) && value.all?{|tuple|
10
+ tuple_type.include?(tuple)
11
+ }
12
+ end
13
+
14
+ # Apply the corresponding TupleType's `dress` to every element of `value`
15
+ # (any enumerable). Return a Set of transformed tuples. Fail if anything
16
+ # goes wrong transforming tuples or if duplicates are found.
17
+ def dress(value, handler = DressHelper.new)
18
+ handler.failed!(self, value) unless value.respond_to?(:each)
19
+
20
+ # Up every tuple and keep results in a Set
21
+ set = Set.new
22
+ handler.iterate(value) do |tuple, index|
23
+ tuple = tuple_type.dress(tuple, handler)
24
+ handler.fail!("Duplicate tuple") if set.include?(tuple)
25
+ set << tuple
26
+ end
27
+
28
+ # Return built tuples
29
+ set
30
+ end
31
+
32
+ private
33
+
34
+ def tuple_type
35
+ @tuple_type ||= begin
36
+ clazz = heading.multi? ? MultiTupleType : TupleType
37
+ clazz.new(heading)
38
+ end
39
+ end
40
+
41
+ end # module RelBasedType
42
+ end # module Finitio