finitio 0.4.1 → 0.5.0

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