algebrick 0.2.5 → 0.3.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.
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