algebrick 0.2.5 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0cdf7449a20fdcad13e1812d823497b9809f4f72
4
- data.tar.gz: 7648901fe0ee4ca913d468480e68418aa5831cd5
3
+ metadata.gz: c01f50d4cf102467631891110b1ee7df7d90375e
4
+ data.tar.gz: ff62352d8e0893a2bc6f4c2d71e183aa6bfbcdb2
5
5
  SHA512:
6
- metadata.gz: da0078b25be0c1426ecff502347f98075d7095192c501bf5f823914c807cd6500d330e16f6e1beb898e780853367ee3ba65d53fe04605f6dcd53b4f2e771123e
7
- data.tar.gz: 72e9e964204e96cd4a6be07167a84c4015ec5c07f63d93cd75a28951328c955880a9cbff8817c58e22ea1385bfacd7fb583106a02d08862bc24292133cec8daa
6
+ metadata.gz: 7b0ac037c8e10a26de02a2194085248f18947034713db0a9cb4d0b687052df3160f73e86ea3715c74f570cd41987e4f99b6bde87e630d96cc4be23f9edc1c9e3
7
+ data.tar.gz: 2ba7c6fb2338c87d9fb51a8e5890d321742e6878ae7e1b10cff9da409b5b4054484340d0f3a6c598f5c22be94fddf6da20e881bebffaf85da74ef0ffd8d72e10
File without changes
data/README_FULL.md CHANGED
@@ -54,6 +54,10 @@ Algebraic matchers are helper objects to match algebraic values and others with
54
54
 
55
55
  {include:file:doc/pattern_matching.out.rb}
56
56
 
57
+ ### Parametrized types
58
+
59
+ {include:file:doc/parametrized.out.rb}
60
+
57
61
  ## What is it good for?
58
62
 
59
63
  ### Defining data with a given structure
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.5
1
+ 0.3.0
data/lib/algebrick.rb CHANGED
@@ -14,24 +14,18 @@
14
14
 
15
15
 
16
16
  # TODO method definition in variant type defines methods on variants based on match, better performance?
17
- # TODO type variables/constructor maybe(a) === none | a
18
17
  # TODO add matcher/s for Hash
19
18
  # TODO add method matcher (:size, matcher)
20
19
  # TODO Menu modeling example, add TypedArray
21
20
  # TODO update actor pattern example when gem is done
22
- # TODO example with birth-number Valid|Invalid
23
21
 
24
- require 'set'
22
+ require 'monitor'
25
23
 
26
- #class Module
27
- # # Return any modules we +extend+
28
- # def extended_modules
29
- # class << self
30
- # self
31
- # end.included_modules
32
- # end
33
- #end
34
24
 
25
+ # Provides Algebraic types and pattern matching
26
+ #
27
+ # **Quick example**
28
+ # {include:file:doc/quick_example.out.rb}
35
29
  module Algebrick
36
30
 
37
31
  def self.version
@@ -75,30 +69,13 @@ module Algebrick
75
69
  end
76
70
  end
77
71
 
72
+ # include this module anywhere yoy need to use pattern matching
78
73
  module Matching
79
74
  def any
80
75
  Matchers::Any.new
81
76
  end
82
77
 
83
- alias_method :_, :any # TODO make it optional
84
-
85
- #match Empty,
86
- # Empty >> static_value_like_string,
87
- # Leaf.(~any) >-> value do
88
- # value
89
- # end
90
- #match Empty,
91
- # Node => ->() {},
92
- # Empty => ->() {},
93
- # Leaf.(~any) => ->(value) { value }
94
- #match Empty,
95
- # [Node, lambda {}],
96
- # [Empty, lambda {}],
97
- # [Leaf.(~any), lambda { |value| value }]
98
- #match(Empty,
99
- # Node.case {},
100
- # Empty.case {},
101
- # Leaf.(~any).case { |value| value })
78
+ alias_method :_, :any
102
79
 
103
80
  def match(value, *cases)
104
81
  cases = if cases.size == 1 && cases.first.is_a?(Hash)
@@ -108,14 +85,14 @@ module Algebrick
108
85
  end
109
86
 
110
87
  cases.each do |matcher, block|
111
- return match_value matcher, block if matcher === value
88
+ return Matching.match_value matcher, block if matcher === value
112
89
  end
113
90
  raise "no match for (#{value.class}) '#{value}' by any of #{cases.map(&:first).join ', '}"
114
91
  end
115
92
 
116
93
  private
117
94
 
118
- def match_value(matcher, block)
95
+ def self.match_value(matcher, block)
119
96
  if block.kind_of? Proc
120
97
  if matcher.kind_of? Matchers::Abstract
121
98
  matcher.assigns &block
@@ -152,10 +129,6 @@ module Algebrick
152
129
  !to_m
153
130
  end
154
131
 
155
- def -(block)
156
- to_m - block
157
- end
158
-
159
132
  def case(&block)
160
133
  to_m.case &block
161
134
  end
@@ -169,6 +142,7 @@ module Algebrick
169
142
  end
170
143
  end
171
144
 
145
+ # Any Algebraic type defined by Algebrick is kind of Type
172
146
  class Type < Module
173
147
  include TypeCheck
174
148
  include Matching
@@ -204,6 +178,7 @@ module Algebrick
204
178
  end
205
179
  end
206
180
 
181
+ # Any value of Algebraic type is kind of Value
207
182
  module Value
208
183
  include TypeCheck
209
184
  include Matching
@@ -232,6 +207,7 @@ module Algebrick
232
207
  TYPE_KEY = :algebrick
233
208
  FIELDS_KEY = :fields
234
209
 
210
+ # Representation of Atomic types
235
211
  class Atom < Type
236
212
  include Value
237
213
 
@@ -273,6 +249,7 @@ module Algebrick
273
249
  end
274
250
  end
275
251
 
252
+ # A private class used for Product values creation
276
253
  class ProductConstructor
277
254
  include Value
278
255
  attr_reader :fields
@@ -338,15 +315,25 @@ module Algebrick
338
315
  end
339
316
  end
340
317
 
318
+ # Representation of Product and Variant types. The class behaves differently
319
+ # based on #kind.
341
320
  class ProductVariant < Type
342
321
  attr_reader :fields, :variants
343
322
 
323
+ def initialize(name, &definition)
324
+ super(name, &definition)
325
+ @to_be_kind_of = []
326
+ end
327
+
344
328
  def set_fields(fields_or_hash)
345
329
  raise TypeError, 'can be set only once' if @fields
346
- fields, keys = if fields_or_hash.size == 1 && fields_or_hash.first.is_a?(Hash)
347
- [fields_or_hash.first.values, fields_or_hash.first.keys]
348
- else
330
+ fields, keys = case fields_or_hash
331
+ when Hash
332
+ [fields_or_hash.values, fields_or_hash.keys]
333
+ when Array
349
334
  [fields_or_hash, nil]
335
+ else
336
+ raise ArgumentError
350
337
  end
351
338
 
352
339
  set_field_names keys if keys
@@ -356,6 +343,8 @@ module Algebrick
356
343
  define_method(:value) { @fields.first } if fields.size == 1
357
344
  @fields = fields
358
345
  @constructor = Class.new(ProductConstructor).tap { |c| c.type = self }
346
+ apply_be_kind_of
347
+ self
359
348
  end
360
349
 
361
350
  def field_names
@@ -387,27 +376,11 @@ module Algebrick
387
376
  add_field_method_readers *@field_names
388
377
  end
389
378
 
390
- raise 'remove deprecation' if Algebrick.version >= Gem::Version.new('0.3')
391
-
392
- def add_all_field_method_accessors
393
- warn "add_all_field_method_accessors is deprecated, it'll be removed in 0.3\n#{caller[0]}"
394
- add_all_field_method_readers
395
- end
396
-
397
- def add_field_method_accessors(*fields)
398
- warn "add_all_field_method_accessors is deprecated, it'll be removed in 0.3\n#{caller[0]}"
399
- add_field_method_readers *fields
400
- end
401
-
402
- def add_field_method_accessor(field)
403
- warn "add_all_field_method_accessors is deprecated, it'll be removed in 0.3\n#{caller[0]}"
404
- add_field_method_reader field
405
- end
406
-
407
379
  def set_variants(variants)
408
380
  raise TypeError, 'can be set only once' if @variants
409
381
  variants.all? { |v| is_kind_of! v, Type, Class }
410
382
  @variants = variants
383
+ apply_be_kind_of
411
384
  variants.each do |v|
412
385
  if v.respond_to? :be_kind_of
413
386
  v.be_kind_of self
@@ -415,10 +388,11 @@ module Algebrick
415
388
  v.send :include, self
416
389
  end
417
390
  end
391
+ self
418
392
  end
419
393
 
420
394
  def new(*fields)
421
- raise TypeError unless @constructor
395
+ raise TypeError, "#{self} does not have fields" unless @constructor
422
396
  @constructor.new *fields
423
397
  end
424
398
 
@@ -430,9 +404,15 @@ module Algebrick
430
404
  end
431
405
 
432
406
  def be_kind_of(type)
433
- kind
434
- @constructor.send :include, type if @constructor
435
- variants.each { |v| v.be_kind_of type unless v == self } if @variants
407
+ @to_be_kind_of << type
408
+ apply_be_kind_of
409
+ end
410
+
411
+ def apply_be_kind_of
412
+ @to_be_kind_of.each do |type|
413
+ @constructor.send :include, type if @constructor
414
+ variants.each { |v| v.be_kind_of type unless v == self } if @variants
415
+ end
436
416
  end
437
417
 
438
418
  def call(*field_matchers)
@@ -500,6 +480,15 @@ module Algebrick
500
480
  end
501
481
  end
502
482
 
483
+ def assigned_types
484
+ @assigned_types or raise TypeError, "#{self} does not have assigned types"
485
+ end
486
+
487
+ def assigned_types=(assigned_types)
488
+ raise TypeError, "#{self} assigned types already set" if @assigned_types
489
+ @assigned_types = assigned_types
490
+ end
491
+
503
492
  private
504
493
 
505
494
  def product_to_s
@@ -559,10 +548,108 @@ module Algebrick
559
548
  end
560
549
  end
561
550
 
551
+ class ParametrizedType < Module
552
+ include TypeCheck
553
+ include MatcherDelegations
554
+
555
+ attr_reader :variables, :fields, :variants
556
+
557
+ def initialize(variables)
558
+ @variables = variables.each { |v| is_kind_of! v, Symbol }
559
+ @fields = nil
560
+ @variants = nil
561
+ @cache = {}
562
+ @cache_barrier = Monitor.new
563
+ end
564
+
565
+ def set_fields(fields)
566
+ @fields = is_kind_of! fields, Hash, Array
567
+ end
568
+
569
+ def field_names
570
+ case @fields
571
+ when Hash
572
+ @fields.keys
573
+ when Array, nil
574
+ raise TypeError, "field names not defined on #{self}"
575
+ else
576
+ raise
577
+ end
578
+ end
579
+
580
+ def set_variants(variants)
581
+ @variants = is_kind_of! variants, Array
582
+ end
583
+
584
+ def [](*assigned_types)
585
+ @cache_barrier.synchronize do
586
+ @cache[assigned_types] || begin
587
+ raise ArgumentError unless assigned_types.size == variables.size
588
+ ProductVariant.new(type_name(assigned_types)).tap do |type|
589
+ type.be_kind_of self
590
+ @cache[assigned_types] = type
591
+ type.assigned_types = assigned_types
592
+ type.set_variants insert_types(variants, assigned_types) if variants
593
+ type.set_fields insert_types(fields, assigned_types) if fields
594
+ end
595
+ end
596
+ end
597
+ end
598
+
599
+ def to_s
600
+ "#{name}[#{variables.join(', ')}]"
601
+ end
602
+
603
+ def inspect
604
+ to_s
605
+ end
606
+
607
+ def to_m
608
+ if @variants
609
+ Matchers::Variant.new self
610
+ else
611
+ Matchers::Product.new self
612
+ end
613
+ end
614
+
615
+ def call(*field_matchers)
616
+ raise TypeError unless @fields
617
+ Matchers::Product.new self, *field_matchers
618
+ end
619
+
620
+ private
621
+
622
+ def insert_types(types, assigned_types)
623
+ case types
624
+ when Hash
625
+ types.inject({}) { |h, (k, v)| h.update k => insert_type(v, assigned_types) }
626
+ when Array
627
+ types.map { |v| insert_type v, assigned_types }
628
+ else
629
+ raise ArgumentError
630
+ end
631
+ end
632
+
633
+ def insert_type(type, assigned_types)
634
+ case type
635
+ when Symbol
636
+ assigned_types[variables.index type]
637
+ when ParametrizedType
638
+ type[*type.variables.map { |v| assigned_types[variables.index v] }]
639
+ else
640
+ type
641
+ end
642
+ end
643
+
644
+ def type_name(assigned_types)
645
+ "#{name}[#{assigned_types.join(', ')}]"
646
+ end
647
+ end
648
+
562
649
  module DSL
563
650
  module Shortcuts
564
- def type(&block)
565
- Algebrick.type &block
651
+ def type(*variables, &block)
652
+ Algebrick.type *variables, &block
566
653
  end
567
654
 
568
655
  def atom
@@ -572,17 +659,18 @@ module Algebrick
572
659
 
573
660
  class TypeDefinitionScope
574
661
  include Shortcuts
662
+ include TypeCheck
575
663
 
576
664
  attr_reader :new_type
577
665
 
578
- def initialize(&block)
579
- @new_type = ProductVariant.new nil
666
+ def initialize(new_type, &block)
667
+ @new_type = is_kind_of! new_type, ProductVariant, ParametrizedType
580
668
  instance_exec @new_type, &block
581
- @new_type.kind
669
+ @new_type.kind if @new_type.is_a? ProductVariant
582
670
  end
583
671
 
584
672
  def fields(*fields)
585
- @new_type.set_fields fields
673
+ @new_type.set_fields fields.first.is_a?(Hash) ? fields.first : fields
586
674
  self
587
675
  end
588
676
 
@@ -620,11 +708,16 @@ module Algebrick
620
708
  end
621
709
  end
622
710
 
623
- def self.type(&block)
711
+ def self.type(*variables, &block)
624
712
  if block.nil?
713
+ raise 'Atom canot be parametrized' unless variables.empty?
625
714
  atom
626
715
  else
627
- DSL::TypeDefinitionScope.new(&block).new_type
716
+ if variables.empty?
717
+ DSL::TypeDefinitionScope.new(ProductVariant.new(nil), &block).new_type
718
+ else
719
+ DSL::TypeDefinitionScope.new(ParametrizedType.new(variables), &block).new_type
720
+ end
628
721
  end
629
722
  end
630
723
 
@@ -650,19 +743,11 @@ module Algebrick
650
743
  return self, block
651
744
  end
652
745
 
653
- raise 'remove deprecation' if Algebrick.version >= Gem::Version.new('0.3')
654
-
655
- def -(block)
656
- warn "a 'matcher --> {}' and 'matcher +-> {}' is deprecated, it'll be removed in 0.3\n#{caller[0]}"
657
- self > block
658
- end
659
-
660
746
  def >(block)
661
747
  return self, block
662
748
  end
663
749
 
664
750
  alias_method :>>, :>
665
- alias_method :+, :-
666
751
 
667
752
  def ~
668
753
  @assign = true
@@ -954,12 +1039,15 @@ module Algebrick
954
1039
 
955
1040
  def initialize(algebraic_type, *field_matchers)
956
1041
  super()
957
- @algebraic_type = is_kind_of! algebraic_type, Algebrick::ProductVariant
1042
+ @algebraic_type = is_kind_of! algebraic_type, Algebrick::ProductVariant, Algebrick::ParametrizedType
958
1043
  raise ArgumentError unless algebraic_type.fields
959
1044
  @field_matchers = case
1045
+
1046
+ # AProduct.()
960
1047
  when field_matchers.empty?
961
1048
  ::Array.new(algebraic_type.fields.size) { Algebrick.any }
962
1049
 
1050
+ # AProduct.(field_name: a_matcher)
963
1051
  when field_matchers.size == 1 && field_matchers.first.is_a?(Hash)
964
1052
  field_matchers = field_matchers.first
965
1053
  unless (dif = field_matchers.keys - algebraic_type.field_names).empty?
@@ -968,7 +1056,9 @@ module Algebrick
968
1056
  algebraic_type.field_names.map do |field|
969
1057
  field_matchers[field] || Algebrick.any
970
1058
  end
971
- when field_matchers.is_a?(::Array) && field_matchers.all? { |v| v.is_a? Symbol }
1059
+
1060
+ # AProduct.(:field_name)
1061
+ when field_matchers.all? { |v| v.is_a? Symbol }
972
1062
  unless (dif = field_matchers - algebraic_type.field_names).empty?
973
1063
  raise ArgumentError, "no #{dif} fields in #{algebraic_type}"
974
1064
  end
@@ -976,6 +1066,7 @@ module Algebrick
976
1066
  field_matchers.include?(field) ? ~Algebrick.any : Algebrick.any
977
1067
  end
978
1068
 
1069
+ # normal
979
1070
  else
980
1071
  field_matchers
981
1072
  end
@@ -1032,565 +1123,4 @@ module Algebrick
1032
1123
  end
1033
1124
  end
1034
1125
 
1035
- #class AbstractProductVariant < Type
1036
- # def be_kind_of(type = nil)
1037
- # if initialized?
1038
- # be_kind_of! type if type
1039
- # if @to_be_kind_of
1040
- # while (type = @to_be_kind_of.shift)
1041
- # be_kind_of! type
1042
- # end
1043
- # end
1044
- # else
1045
- # @to_be_kind_of ||= []
1046
- # @to_be_kind_of << type if type
1047
- # end
1048
- # self
1049
- # end
1050
- #
1051
- # def add_field_method_accessor(field)
1052
- # raise TypeError, 'no field names' unless @field_names
1053
- # raise TypeError, "no field name #{field}" unless @field_names.include? field
1054
- # define_method(field) { self[field] }
1055
- # self
1056
- # end
1057
- #
1058
- # def add_field_method_accessors(*fields)
1059
- # fields.each { |f| add_field_method_accessor f }
1060
- # self
1061
- # end
1062
- #
1063
- # def add_all_field_method_accessors
1064
- # add_field_method_accessors *@field_names
1065
- # end
1066
- #
1067
- # protected
1068
- #
1069
- # def be_kind_of!(type)
1070
- # raise NotImplementedError
1071
- # end
1072
- #
1073
- # private
1074
- #
1075
- # def initialized?
1076
- # !!@initialized
1077
- # end
1078
- #
1079
- # def initialize(name, &block)
1080
- # super name, &block
1081
- # @initialized = true
1082
- # be_kind_of
1083
- # end
1084
- #
1085
- # def set_fields(fields_or_hash)
1086
- # fields, keys = if fields_or_hash.size == 1 && fields_or_hash.first.is_a?(Hash)
1087
- # [fields_or_hash.first.values, fields_or_hash.first.keys]
1088
- # else
1089
- # [fields_or_hash, nil]
1090
- # end
1091
- #
1092
- # set_field_names keys if keys
1093
- #
1094
- # fields.all? { |f| is_kind_of! f, Type, Class }
1095
- # raise TypeError, 'there is no product with zero fields' unless fields.size > 0
1096
- # define_method(:value) { @fields.first } if fields.size == 1
1097
- # @fields = fields
1098
- # @constructor = Class.new(ProductConstructor).tap { |c| c.type = self }
1099
- # end
1100
- #
1101
- # def set_field_names(names)
1102
- # @field_names = names
1103
- # names.all? { |k| is_kind_of! k, Symbol }
1104
- # dict = @field_indexes =
1105
- # Hash.new { |h, k| raise ArgumentError, "unknown field #{k.inspect} in #{self}" }.
1106
- # update names.each_with_index.inject({}) { |h, (k, i)| h.update k => i }
1107
- # define_method(:[]) { |key| @fields[dict[key]] }
1108
- # end
1109
- #
1110
- # def set_variants(variants)
1111
- # variants.all? { |v| is_kind_of! v, Type, Class }
1112
- # @variants = variants
1113
- # variants.each do |v|
1114
- # if v.respond_to? :be_kind_of
1115
- # v.be_kind_of self
1116
- # else
1117
- # v.send :include, self
1118
- # end
1119
- # end
1120
- # end
1121
- #
1122
- # def product_be_kind_of(type)
1123
- # @constructor.send :include, type
1124
- # end
1125
- #
1126
- # def construct_product(*fields)
1127
- # @constructor.new *fields
1128
- # end
1129
- #
1130
- # def product_to_s
1131
- # fields_str = if field_names
1132
- # field_names.zip(fields).map { |name, field| "#{name}: #{field.name}" }
1133
- # else
1134
- # fields.map(&:name)
1135
- # end
1136
- # "#{name}(#{fields_str.join ', '})"
1137
- # end
1138
- #
1139
- # def product_from_hash(hash)
1140
- # (type_name = hash[TYPE_KEY] || hash[TYPE_KEY.to_s]) or
1141
- # raise ArgumentError, "hash does not have #{TYPE_KEY}"
1142
- # raise ArgumentError, "#{type_name} is not #{name}" unless type_name == name
1143
- #
1144
- # fields = hash[FIELDS_KEY] || hash[FIELDS_KEY.to_s] ||
1145
- # hash.reject { |k, _| k.to_s == TYPE_KEY.to_s }
1146
- # is_kind_of! fields, Hash, Array
1147
- #
1148
- # case fields
1149
- # when Array
1150
- # self[*fields.map { |value| field_from_hash value }]
1151
- # when Hash
1152
- # self[fields.inject({}) do |h, (name, value)|
1153
- # raise ArgumentError unless @field_names.map(&:to_s).include? name.to_s
1154
- # h.update name.to_sym => field_from_hash(value)
1155
- # end]
1156
- # end
1157
- # end
1158
- #
1159
- # def field_from_hash(hash)
1160
- # return hash unless Hash === hash
1161
- # (type_name = hash[TYPE_KEY] || hash[TYPE_KEY.to_s]) or return hash
1162
- # type = constantize type_name
1163
- # type.from_hash hash
1164
- # end
1165
- #
1166
- # def constantize(camel_cased_word)
1167
- # names = camel_cased_word.split('::')
1168
- # names.shift if names.empty? || names.first.empty?
1169
- #
1170
- # constant = Object
1171
- # names.each do |name|
1172
- # constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
1173
- # end
1174
- # constant
1175
- # end
1176
- #end
1177
- #
1178
- #class Product < AbstractProductVariant
1179
- # attr_reader :fields, :field_names, :field_indexes
1180
- #
1181
- # def initialize(name, *fields, &block)
1182
- # set_fields fields
1183
- # super(name, &block)
1184
- # end
1185
- #
1186
- # def new(*fields)
1187
- # construct_product(*fields)
1188
- # end
1189
- #
1190
- # alias_method :[], :new
1191
- #
1192
- # def be_kind_of!(type)
1193
- # product_be_kind_of type
1194
- # end
1195
- #
1196
- # def call(*field_matchers)
1197
- # Matchers::Product.new self, *field_matchers
1198
- # end
1199
- #
1200
- # def to_m
1201
- # call *::Array.new(fields.size) { Algebrick.any }
1202
- # end
1203
- #
1204
- # def ==(other)
1205
- # other.kind_of? Product and fields == other.fields
1206
- # end
1207
- #
1208
- # def to_s
1209
- # product_to_s
1210
- # end
1211
- #
1212
- # def from_hash(hash)
1213
- # product_from_hash hash
1214
- # end
1215
- #end
1216
- #
1217
- #class Variant < AbstractProductVariant
1218
- # attr_reader :variants
1219
- #
1220
- # def initialize(name, *variants, &block)
1221
- # set_variants(variants)
1222
- # super name, &block
1223
- # end
1224
- #
1225
- # def be_kind_of!(type)
1226
- # variants.each { |v| v.be_kind_of type }
1227
- # end
1228
- #
1229
- # def to_m
1230
- # Matchers::Variant.new self
1231
- # end
1232
- #
1233
- # def ==(other)
1234
- # other.kind_of? Variant and variants == other.variants
1235
- # end
1236
- #
1237
- # def to_s
1238
- # "#{name}(#{variants.map(&:name).join ' | '})"
1239
- # end
1240
- #
1241
- # def from_hash(hash)
1242
- # field_from_hash hash
1243
- # end
1244
- #end
1245
- #
1246
- #class ProductVariant < AbstractProductVariant
1247
- # attr_reader :fields, :field_names, :field_indexes, :variants
1248
- #
1249
- # def initialize(name, fields, variants, &block)
1250
- # set_fields fields
1251
- # raise unless variants.include? self
1252
- # set_variants variants
1253
- # super name, &block
1254
- # end
1255
- #
1256
- # def be_kind_of!(type)
1257
- # variants.each { |v| v.be_kind_of type unless v == self }
1258
- # product_be_kind_of type
1259
- # end
1260
- #
1261
- # def call(*field_matchers)
1262
- # Matchers::Product.new self, *field_matchers
1263
- # end
1264
- #
1265
- # def to_m
1266
- # Matchers::Variant.new self
1267
- # end
1268
- #
1269
- # def new(*fields)
1270
- # construct_product(*fields)
1271
- # end
1272
- #
1273
- # alias_method :[], :new
1274
- #
1275
- # def ==(other)
1276
- # other.kind_of? ProductVariant and
1277
- # variants == other.variants and fields == other.fields
1278
- # end
1279
- #
1280
- # def to_s
1281
- # name + '(' +
1282
- # variants.map do |variant|
1283
- # if variant == self
1284
- # product_to_s
1285
- # else
1286
- # variant.name
1287
- # end
1288
- # end.join(' | ') +
1289
- # ')'
1290
- # end
1291
- #
1292
- # def from_hash(hash)
1293
- # product_from_hash hash
1294
- # end
1295
- #end
1296
-
1297
- #module DSL
1298
- # -> do
1299
- # maybe[:a] === none | some(:a)
1300
- # tree[:a] === tip | tree(:a, tree, tree)
1301
- # end
1302
- #
1303
- # -> do
1304
- # maybe[:a].can_be none,
1305
- # some.has(:a)
1306
- #
1307
- # maybe[:a].can_be none,
1308
- # some.having(:a)
1309
- #
1310
- # maybe[:a].can_be none,
1311
- # some.having(:a)
1312
- # tree.can_be tip,
1313
- # tree.having(Object, tree, tree)
1314
- #
1315
- # tree.can_be empty,
1316
- # leaf.having(Object),
1317
- # node.having(left: tree, right: tree)
1318
- #
1319
- # tree do
1320
- # # def ...
1321
- # end
1322
- # end
1323
- #
1324
- # class PreType
1325
- # include TypeCheck
1326
- #
1327
- # attr_reader :environment, :name, :fields, :variants, :definition, :variables
1328
- #
1329
- # def initialize(environment, name)
1330
- # @environment = is_kind_of! environment, Environment
1331
- # @name = is_kind_of! name, String
1332
- # @fields = []
1333
- # @variables = []
1334
- # @variants = []
1335
- # @definition = nil
1336
- # end
1337
- #
1338
- # def const_name
1339
- # @const_name ||= name.to_s.split('_').map { |s| s.tap { s[0] = s[0].upcase } }.join
1340
- # end
1341
- #
1342
- # #def |(other)
1343
- # # [self, other]
1344
- # #end
1345
- # #
1346
- # #def to_ary
1347
- # # [self]
1348
- # #end
1349
- #
1350
- # def [](*variables)
1351
- # variables.all? { |var| is_kind_of! var, Symbol }
1352
- # @variables += variables
1353
- # self
1354
- # end
1355
- #
1356
- # def fields=(fields)
1357
- # raise 'fields can be defined only once' unless @fields.empty?
1358
- # fields.each do |field|
1359
- # if Hash === field
1360
- # field.each do |k, v|
1361
- # is_kind_of! k, Symbol
1362
- # is_kind_of! v, PreType, Type, Class, Symbol
1363
- # @variables.push v if v.is_a? Symbol
1364
- # end
1365
- # else
1366
- # is_kind_of! field, PreType, Type, Class, Symbol
1367
- # @variables += fields.select { |v| v.is_a? Symbol }
1368
- # end
1369
- # end
1370
- # @fields += fields
1371
- # end
1372
- #
1373
- # def having(fields)
1374
- # self.fields = fields
1375
- # self
1376
- # end
1377
- #
1378
- # alias_method :has, :having
1379
- #
1380
- # def fields_array
1381
- # if (hash = @fields.find { |f| Hash === f })
1382
- # hash.values
1383
- # else
1384
- # @fields
1385
- # end
1386
- # end
1387
- #
1388
- # #def dependent(set = Set.new)
1389
- # # children = @variants + @fields
1390
- # # children.each do |a_type|
1391
- # # next if set.include? a_type
1392
- # # next unless a_type.respond_to? :dependent
1393
- # # set.add a_type
1394
- # # a_type.dependent set
1395
- # # end
1396
- # # set.to_a
1397
- # #end
1398
- #
1399
- # def definition=(block)
1400
- # raise 'definition can be defined only once' if @definition
1401
- # @definition = block
1402
- # end
1403
- #
1404
- # def can_be(*variants)
1405
- # raise 'variants can be defined only once' unless @variants.empty?
1406
- # @variants = variants
1407
- # self
1408
- # end
1409
- #
1410
- # def no_variables?
1411
- # !variables? and fields_array.select { |f| Symbol === f }.empty?
1412
- # end
1413
- #
1414
- # def variables?
1415
- # not @variables.empty?
1416
- # end
1417
- #
1418
- # def kind
1419
- # unless @variants.empty?
1420
- # if @fields.empty?
1421
- # Variant
1422
- # else
1423
- # ProductVariant
1424
- # end
1425
- # else
1426
- # if @fields.empty?
1427
- # Atom
1428
- # else
1429
- # Product
1430
- # end
1431
- # end
1432
- # end
1433
- # end
1434
- #
1435
- # class TypeConstructor
1436
- # include TypeCheck
1437
- # attr_reader :const_name
1438
- #
1439
- # def initialize(pre_types, const_name, variables)
1440
- # warn "types with variables are experimental\n#{caller[0]}"
1441
- # @pre_types = is_kind_of! pre_types, Hash
1442
- # @const_name = is_kind_of! const_name, String
1443
- # @variables = is_kind_of! variables, Array
1444
- # @cache = {}
1445
- # end
1446
- #
1447
- # def [](*variables)
1448
- # variables.size == @variables.size or
1449
- # raise ArgumentError, "variables size differs from #{@variables}"
1450
- # @cache[variables] ||= begin
1451
- #
1452
- # TypeFactory.new(@pre_types, Hash[@variables.zip(variables)]).define.tap do |types|
1453
- # types.each do |name, type|
1454
- #
1455
- # end
1456
- # end
1457
- # end
1458
- # end
1459
- #
1460
- # def to_s
1461
- # const_name + @variables.inspect
1462
- # end
1463
- #
1464
- # def inspect
1465
- # to_s
1466
- # end
1467
- # end
1468
- #
1469
- # class TypeFactory
1470
- # include TypeCheck
1471
- #
1472
- # def initialize(pre_types, variable_mapping)
1473
- # @pre_types = is_kind_of! pre_types, Hash
1474
- # @variable_mapping = is_kind_of! variable_mapping, Hash
1475
- # @types = {}
1476
- # end
1477
- #
1478
- # def define
1479
- # define_types
1480
- # define_fields_and_variants
1481
- # eval_definitions
1482
- #
1483
- # @types
1484
- # end
1485
- #
1486
- # private
1487
- #
1488
- # def define_types
1489
- # @pre_types.each do |name, pre_type|
1490
- # @types[name] = pre_type.kind.allocate
1491
- # end
1492
- # end
1493
- #
1494
- # def define_fields_and_variants
1495
- # select = ->(klass, &block) do
1496
- # @pre_types.select { |_, pre_type| pre_type.kind == klass }.each &block
1497
- # end
1498
- #
1499
- # select.(Atom) do |name, pre_type|
1500
- # @types[name].send :initialize, type_name(pre_type)
1501
- # end
1502
- #
1503
- # select.(Product) do |name, pre_type|
1504
- # @types[name].send :initialize, type_name(pre_type), *pre_type.fields.map { |f| get_class f }
1505
- # end
1506
- #
1507
- # select.(Variant) do |name, pre_type|
1508
- # @types[name].send :initialize, type_name(pre_type), *pre_type.variants.map { |v| get_class v }
1509
- # end
1510
- #
1511
- # select.(ProductVariant) do |name, pre_type|
1512
- # @types[name].send :initialize, type_name(pre_type),
1513
- # pre_type.fields.map { |f| get_class f },
1514
- # pre_type.variants.map { |v| get_class v }
1515
- # end
1516
- # end
1517
- #
1518
- # def eval_definitions
1519
- # @pre_types.each do |name, pre_type|
1520
- # next unless pre_type.definition
1521
- # type = get_class name
1522
- # type.module_eval &pre_type.definition
1523
- # end
1524
- # end
1525
- #
1526
- # def get_class(key)
1527
- # if key.kind_of? Symbol
1528
- # @variable_mapping[key] or raise "missing variable mapping for #{key}"
1529
- # elsif key.kind_of? String
1530
- # @types[key] or raise ArgumentError
1531
- # elsif key.kind_of? PreType
1532
- # @types[key.name]
1533
- # elsif key.kind_of? Hash
1534
- # key.each { |k, v| key[k] = get_class v }
1535
- # else
1536
- # key
1537
- # end
1538
- # end
1539
- #
1540
- # def type_name(pre_type)
1541
- # pre_type.const_name + if pre_type.variables?
1542
- # '[' + pre_type.variables.map { |v| @variable_mapping[v] } * ',' + ']'
1543
- # else
1544
- # ''
1545
- # end
1546
- # end
1547
- # end
1548
- #
1549
- # class Environment
1550
- # attr_reader :pre_types
1551
- # def initialize(&definition)
1552
- # @pre_types = {}
1553
- # @types = {}
1554
- # instance_eval &definition
1555
- # end
1556
- #
1557
- # def method_missing(method, *fields, &definition)
1558
- # name = method.to_s
1559
- # @pre_types[name] ||= PreType.new(self, name)
1560
- # @pre_types[name].fields = fields unless fields.empty?
1561
- # @pre_types[name].definition = definition if definition
1562
- # @pre_types[name]
1563
- # end
1564
- #
1565
- # def run
1566
- # pre_types = @pre_types.select { |_, pt| pt.no_variables? }
1567
- # types = TypeFactory.new(pre_types, {}).define
1568
- # constants = pre_types.inject({}) do |hash, (name, pre_type)|
1569
- # hash.update pre_type.const_name => types[name]
1570
- # end
1571
- #
1572
- # pre_constructors = @pre_types.select { |_, pt| pt.variables? }
1573
- # constructors = pre_constructors.inject({}) do |hash, (name, pt)|
1574
- # pre_types = Hash[([pt] + pt.dependent).map { |pt| [pt.name, pt] }]
1575
- # hash.update name => TypeConstructor.new(pre_types, pt.const_name, pt.variables)
1576
- # end
1577
- #
1578
- # constants.update Hash[constructors.map { |name, c| [c.const_name, c] }]
1579
- #
1580
- # @pre_types.map { |name, pre_type| types[name] || constructors[name] || raise("missing #{name}") }
1581
- # end
1582
- #
1583
- # private
1584
- #
1585
- # #def define_constants(map)
1586
- # # map.each { |const_name, value| @base.const_set const_name.to_sym, value } if @base
1587
- # #end
1588
- # end
1589
- #
1590
- # def type_def(&definition)
1591
- # Environment.new(&definition).run
1592
- # end
1593
- #end
1594
-
1595
- #extend DSL
1596
1126
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: algebrick
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Petr Chalupa
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-09-26 00:00:00.000000000 Z
11
+ date: 2013-10-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: redcarpet
84
+ name: kramdown
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - '>='
@@ -127,14 +127,14 @@ email: git@pitr.ch
127
127
  executables: []
128
128
  extensions: []
129
129
  extra_rdoc_files:
130
- - LICENSE
130
+ - LICENSE.txt
131
131
  - README.md
132
132
  - README_FULL.md
133
133
  - VERSION
134
134
  files:
135
135
  - lib/algebrick.rb
136
136
  - VERSION
137
- - LICENSE
137
+ - LICENSE.txt
138
138
  - README.md
139
139
  - README_FULL.md
140
140
  homepage: https://github.com/pitr-ch/algebrick