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
@@ -0,0 +1,33 @@
1
+ module Finitio
2
+ class Contract
3
+ include Metadata
4
+
5
+ def initialize(infotype, dresser, undresser, name = nil, metadata = nil)
6
+ unless infotype.is_a?(Type)
7
+ raise ArgumentError, "Type expected, got `#{infotype}`"
8
+ end
9
+ unless dresser.respond_to?(:call)
10
+ raise ArgumentError, "r(:call) expected, got `#{dresser}`"
11
+ end
12
+ unless undresser.respond_to?(:call)
13
+ raise ArgumentError, "r(:call) expected, got `#{undresser}`"
14
+ end
15
+ unless name.nil? or name.is_a?(Symbol)
16
+ raise ArgumentError, "Symbol expected, got `#{name}`"
17
+ end
18
+
19
+ @name = name
20
+ @infotype = infotype
21
+ @dresser = dresser
22
+ @undresser = undresser
23
+ @metadata = metadata
24
+ end
25
+ attr_reader :name, :infotype, :dresser, :undresser
26
+
27
+ def bind_ruby_type(clazz)
28
+ @dresser = clazz.method(name.to_sym)
29
+ @undresser = clazz.instance_method(:"to_#{name}")
30
+ end
31
+
32
+ end # class Contract
33
+ end # module Finitio
@@ -24,7 +24,8 @@ module Finitio
24
24
  def just_try(rescue_on = TypeError)
25
25
  [ true, yield ]
26
26
  rescue rescue_on => cause
27
- [ false, nil ]
27
+ #STDERR.puts cause.inspect
28
+ [ false, cause ]
28
29
  end
29
30
 
30
31
  def try(type, value)
@@ -44,7 +45,7 @@ module Finitio
44
45
 
45
46
  def default_error_message(type, value)
46
47
  value_s, type_s = value_to_s(value), type_to_s(type)
47
- "Invalid value `#{value_s}` for #{type_s}"
48
+ "Invalid #{type_s} `#{value_s}`"
48
49
  end
49
50
 
50
51
  def location
@@ -8,20 +8,21 @@ module Finitio
8
8
  class Heading
9
9
  include Enumerable
10
10
 
11
- def initialize(attributes)
12
- unless attributes.is_a?(Enumerable) and \
13
- attributes.all?{|a| a.is_a?(Attribute) }
14
- raise ArgumentError, "Enumerable[Attribute] expected"
15
- end
11
+ DEFAULT_OPTIONS = { allow_extra: false }.freeze
16
12
 
17
- @attributes = {}
18
- attributes.each do |attr|
19
- if @attributes[attr.name]
20
- raise ArgumentError, "Attribute names must be unique"
21
- end
22
- @attributes[attr.name] = attr
13
+ def initialize(attributes, options = nil)
14
+ @attributes = normalize_attributes(attributes)
15
+ @options = normalize_options(options)
16
+ end
17
+
18
+ def [](attrname)
19
+ @attributes[attrname]
20
+ end
21
+
22
+ def fetch(attrname)
23
+ @attributes.fetch(attrname) do
24
+ raise Error, "No such attribute `#{attrname}`"
23
25
  end
24
- @attributes.freeze
25
26
  end
26
27
 
27
28
  def size
@@ -32,26 +33,65 @@ module Finitio
32
33
  size == 0
33
34
  end
34
35
 
36
+ def multi?
37
+ allow_extra? || any?{|attr| not(attr.required?) }
38
+ end
39
+
40
+ def allow_extra?
41
+ options[:allow_extra]
42
+ end
43
+
35
44
  def each(&bl)
36
45
  return to_enum unless bl
37
46
  @attributes.values.each(&bl)
38
47
  end
39
48
 
40
49
  def to_name
41
- map(&:to_name).join(', ')
50
+ name = map(&:to_name).join(', ')
51
+ if allow_extra?
52
+ name << ", " unless empty?
53
+ name << "..."
54
+ end
55
+ name
42
56
  end
43
57
 
44
58
  def ==(other)
45
59
  return nil unless other.is_a?(Heading)
46
- attributes == other.attributes
60
+ attributes == other.attributes && options == other.options
47
61
  end
48
62
 
49
63
  def hash
50
- self.class.hash ^ attributes.hash
64
+ self.class.hash ^ attributes.hash ^ options.hash
51
65
  end
52
66
 
53
- attr_reader :attributes
54
- protected :attributes
67
+ attr_reader :attributes, :options
68
+ protected :attributes, :options
69
+
70
+ private
71
+
72
+ def normalize_attributes(attrs)
73
+ unless attrs.respond_to?(:each)
74
+ raise ArgumentError, "Enumerable[Attribute] expected"
75
+ end
76
+
77
+ attributes = {}
78
+ attrs.each do |attr|
79
+ unless attr.is_a?(Attribute)
80
+ raise ArgumentError, "Enumerable[Attribute] expected"
81
+ end
82
+ if attributes[attr.name]
83
+ raise ArgumentError, "Attribute names must be unique"
84
+ end
85
+ attributes[attr.name] = attr
86
+ end
87
+ attributes.freeze
88
+ end
89
+
90
+ def normalize_options(opts)
91
+ options = DEFAULT_OPTIONS
92
+ options = options.merge(opts).freeze if opts
93
+ options
94
+ end
55
95
 
56
96
  end # class Heading
57
97
  end # class Finitio
@@ -0,0 +1,20 @@
1
+ module Finitio
2
+ module Metadata
3
+
4
+ EMPTY_METADATA = {}.freeze
5
+
6
+ def metadata
7
+ @metadata || EMPTY_METADATA
8
+ end
9
+
10
+ def metadata?
11
+ !@metadata.nil?
12
+ end
13
+
14
+ def metadata=(hash)
15
+ raise "Metadata already set to #{@metadata.inspect}" unless @metadata.nil?
16
+ @metadata = hash
17
+ end
18
+
19
+ end # module Metadata
20
+ end # module Finitio
@@ -1,30 +1,63 @@
1
1
  module Finitio
2
2
  class TypeFactory
3
3
 
4
+ DSL_METHODS = [
5
+ :attribute,
6
+ :heading,
7
+ :constraint,
8
+ :constraints,
9
+ :contract,
10
+ :contracts,
11
+ :any,
12
+ :builtin,
13
+ :adt,
14
+ :subtype,
15
+ :union,
16
+ :seq,
17
+ :set,
18
+ :struct,
19
+ :tuple,
20
+ :multi_tuple,
21
+ :relation,
22
+ :multi_relation,
23
+ :type,
24
+ :proxy
25
+ ]
26
+
4
27
  ################################################################## Factory
5
28
 
6
- def type(type, name = nil, &bl)
7
- return subtype(type(type, name), bl) if bl
29
+ def type(type, name = nil, metadata = nil, &bl)
30
+ return subtype(type(type, name, metadata), bl) if bl
8
31
  case type
9
32
  when Type
10
- type
33
+ alias_type(type, name, metadata)
11
34
  when Module
12
- BuiltinType.new(type, name || type.name.to_s)
35
+ BuiltinType.new(type, name || type.name.to_s, metadata)
13
36
  when Hash
14
- tuple(type, name)
37
+ tuple(type, name, metadata)
15
38
  when Array
16
- fail!("Array of arity 1 expected, got `#{type}`") unless type.size==1
17
- seq(type.first, name)
39
+ case type.size
40
+ when 0
41
+ fail!("Array of arity > 0 expected, got `#{type}`")
42
+ when 1
43
+ seq(type.first, name, metadata)
44
+ else
45
+ struct(type, name, metadata)
46
+ end
18
47
  when Set
19
48
  fail!("Set of arity 1 expected, got `#{type}`") unless type.size==1
20
49
  sub = type(type.first)
21
- sub.is_a?(TupleType) ? relation(sub.heading, name) : set(sub, name)
50
+ if sub.is_a?(TupleType)
51
+ relation(sub.heading, name, metadata)
52
+ else
53
+ set(sub, name, metadata)
54
+ end
22
55
  when Range
23
56
  clazz = [type.begin, type.end].map(&:class).uniq
24
57
  fail!("Unsupported range `#{type}`") unless clazz.size==1
25
- subtype(clazz.first, type)
58
+ subtype(clazz.first, type, name, metadata)
26
59
  when Regexp
27
- subtype(String, type)
60
+ subtype(String, type, name, metadata)
28
61
  else
29
62
  fail!("Unable to factor a Finitio::Type from `#{type}`")
30
63
  end
@@ -48,16 +81,41 @@ module Finitio
48
81
  name.nil? ? nil : name.strip
49
82
  end
50
83
 
84
+ def metadata(metadata)
85
+ unless metadata.nil? or metadata.is_a?(Hash)
86
+ fail!("Wrong metadata `#{metadata}`")
87
+ end
88
+
89
+ metadata
90
+ end
91
+
92
+ def constraint(constraint, name = nil)
93
+ case constraint
94
+ when Constraint then constraint
95
+ else Constraint.new(constraint, name)
96
+ end
97
+ end
98
+
51
99
  def constraints(constraints = nil, &bl)
52
- constrs = {}
53
- constrs[:predicate] = bl if bl
54
- constrs[:predicate] = constraints unless constraints.is_a?(Hash)
55
- constrs.merge!(constraints) if constraints.is_a?(Hash)
100
+ constrs = []
101
+ constrs << Constraint.new(bl) if bl
102
+ case constraints
103
+ when Hash
104
+ constraints.each_pair do |name, cstr|
105
+ constrs << constraint(cstr, name)
106
+ end
107
+ when Array
108
+ constraints.each do |c|
109
+ constrs << constraint(c)
110
+ end
111
+ else
112
+ constrs << Constraint.new(constraints)
113
+ end
56
114
  constrs
57
115
  end
58
116
 
59
- def attribute(name, type)
60
- Attribute.new(name, type(type))
117
+ def attribute(name, type, required = true, metadata = nil)
118
+ Attribute.new(name, type(type), required, metadata)
61
119
  end
62
120
 
63
121
  def attributes(attributes)
@@ -84,52 +142,64 @@ module Finitio
84
142
  end
85
143
  end
86
144
 
145
+ def contract(infotype, dresser, undresser, name = nil, metadata = nil)
146
+ infotype = type(infotype)
147
+ Contract.new(infotype, dresser, undresser, name, metadata)
148
+ end
149
+
87
150
  def contracts(contracts)
88
- unless contracts.is_a?(Hash)
89
- fail!("Hash expected, got `#{contracts}`")
90
- end
91
- unless (invalid = contracts.keys.reject{|k| k.is_a?(Symbol) }).empty?
92
- fail!("Invalid contract names `#{invalid}`")
151
+ case contracts
152
+ when Array
153
+ unless contracts.all?{|c| c.is_a?(Contract) }
154
+ fail!("[Contract] expected, got `#{contracts}`")
155
+ end
156
+ contracts
157
+ when Hash
158
+ contracts.map do |k,v|
159
+ contract(*v.push(k.to_sym))
160
+ end
93
161
  end
94
-
95
- contracts
96
162
  end
97
163
 
98
164
  ########################################################## Type generators
99
165
 
100
- def any(name = nil)
166
+ def any(name = nil, metadata = nil)
101
167
  name = name(name)
168
+ meta = metadata(metadata)
102
169
 
103
- AnyType.new(name)
170
+ AnyType.new(name, meta)
104
171
  end
105
172
 
106
- def builtin(ruby_type, name = nil)
173
+ def builtin(ruby_type, name = nil, metadata = nil)
107
174
  ruby_type = ruby_type(ruby_type)
108
175
  name = name(name)
176
+ meta = metadata(metadata)
109
177
 
110
- BuiltinType.new(ruby_type, name)
178
+ BuiltinType.new(ruby_type, name, meta)
111
179
  end
112
180
 
113
- def adt(ruby_type, contracts, name = nil)
181
+ def adt(ruby_type, contracts, name = nil, metadata = nil)
114
182
  ruby_type = ruby_type(ruby_type) if ruby_type
115
183
  contracts = contracts(contracts)
116
184
  name = name(name)
185
+ meta = metadata(metadata)
117
186
 
118
- AdType.new(ruby_type, contracts, name)
187
+ AdType.new(ruby_type, contracts, name, meta)
119
188
  end
120
189
 
121
190
  ### Sub and union
122
191
 
123
- def subtype(super_type, constraints = nil, name = nil, &bl)
192
+ def subtype(super_type, constraints = nil, name = nil, metadata = nil, &bl)
124
193
  super_type = type(super_type)
125
194
  constraints = constraints(constraints, &bl)
126
195
  name = name(name)
196
+ meta = metadata(metadata)
127
197
 
128
- SubType.new(super_type, constraints, name)
198
+ SubType.new(super_type, constraints, name, metadata)
129
199
  end
130
200
 
131
201
  def union(*args)
132
- candidates, name = [], nil
202
+ candidates, name, meta = [], nil, nil
133
203
  args.each do |arg|
134
204
  case arg
135
205
  when Array then candidates = arg.map{|t| type(t) }
@@ -139,43 +209,86 @@ module Finitio
139
209
  end
140
210
  end
141
211
 
142
- UnionType.new(candidates, name)
212
+ UnionType.new(candidates, name, meta)
143
213
  end
144
214
 
145
215
  ### Collections
146
216
 
147
- def seq(elm_type, name = nil)
217
+ def seq(elm_type, name = nil, metadata = nil)
148
218
  elm_type = type(elm_type)
149
219
  name = name(name)
220
+ meta = metadata(metadata)
150
221
 
151
- SeqType.new(elm_type, name)
222
+ SeqType.new(elm_type, name, meta)
152
223
  end
153
224
 
154
- def set(elm_type, name = nil)
225
+ def set(elm_type, name = nil, metadata = nil)
155
226
  elm_type = type(elm_type)
156
227
  name = name(name)
228
+ meta = metadata(metadata)
229
+
230
+ SetType.new(elm_type, name, meta)
231
+ end
232
+
233
+ def struct(component_types, name = nil, metadata = nil)
234
+ component_types = component_types.map{|t| type(t) }
235
+ name = name(name)
236
+ meta = metadata(metadata)
157
237
 
158
- SetType.new(elm_type, name)
238
+ StructType.new(component_types, name, meta)
159
239
  end
160
240
 
161
241
  ### Tuples and relations
162
242
 
163
- def tuple(heading, name = nil)
243
+ def tuple(heading, name = nil, metadata = nil)
164
244
  heading = heading(heading)
165
245
  name = name(name)
246
+ meta = metadata(metadata)
166
247
 
167
- TupleType.new(heading, name)
248
+ TupleType.new(heading, name, meta)
168
249
  end
169
250
 
170
- def relation(heading, name = nil)
251
+ def multi_tuple(heading, name = nil, metadata = nil)
171
252
  heading = heading(heading)
172
253
  name = name(name)
254
+ meta = metadata(metadata)
173
255
 
174
- RelationType.new(heading, name)
256
+ MultiTupleType.new(heading, name, meta)
257
+ end
258
+
259
+ def relation(heading, name = nil, metadata = nil)
260
+ heading = heading(heading)
261
+ name = name(name)
262
+ meta = metadata(metadata)
263
+
264
+ RelationType.new(heading, name, meta)
265
+ end
266
+
267
+ def multi_relation(heading, name = nil, metadata = nil)
268
+ heading = heading(heading)
269
+ name = name(name)
270
+ meta = metadata(metadata)
271
+
272
+ MultiRelationType.new(heading, name, meta)
273
+ end
274
+
275
+ def proxy(target_name)
276
+ ProxyType.new(target_name)
175
277
  end
176
278
 
177
279
  private
178
280
 
281
+ def alias_type(type, name, metadata)
282
+ raise "Type expected `#{type}`" unless type.is_a?(Type)
283
+ if (name && type.named?) or (metadata && type.metadata?)
284
+ AliasType.new(type, name, metadata)
285
+ else
286
+ type.name = name if name
287
+ type.metadata = metadata if metadata
288
+ type
289
+ end
290
+ end
291
+
179
292
  def fail!(message)
180
293
  raise ArgumentError, message, caller
181
294
  end