algebrick 0.1.2 → 0.1.3

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: 986e5746d10e9a2e2edf3c25da212fff33719dee
4
- data.tar.gz: a711d19897aa1c4085948aa21cace8a86ede5ef6
3
+ metadata.gz: fb30a6eeabbe7769c1f946395bef047d5acf4362
4
+ data.tar.gz: 5c0289625f919dffe3f57e6fa2e258ca353d4ba9
5
5
  SHA512:
6
- metadata.gz: 5c0264da1e050dab04f2238905fab10b253762c68bcaa3c80103a6c4366efb236c003c3b8ce06cba03b0a0a7913f63662bf9246181237215881c99c77856d14a
7
- data.tar.gz: 52d55de9dd00eebb7b6e38959cbf8bae0add19090ff04213a58a053f30389ef313669c41831848d5bf942f6a11274e4c1729f21dbd3b77256d1f4b2c02cac1dc
6
+ metadata.gz: 0932e96464a044f3e2a9138efcd07433bf17fb747f1718b73354599750b84543e70f7b29a97db0854343f6f25c04eda02bc6baa8498a90e5feb55f2ac57437ad
7
+ data.tar.gz: 7bf6898feafadd9694cf898b61c81c9879fcc0dc628044244eed4f9ec5c8d1b3d2888b826305a73d463e08621f79e6759a75b5c84283a4bb48c617d27469671f
data/LICENSE ADDED
@@ -0,0 +1,191 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction, and
10
+ distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by the copyright
13
+ owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all other entities
16
+ that control, are controlled by, or are under common control with that entity.
17
+ For the purposes of this definition, "control" means (i) the power, direct or
18
+ indirect, to cause the direction or management of such entity, whether by
19
+ contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
20
+ outstanding shares, or (iii) beneficial ownership of such entity.
21
+
22
+ "You" (or "Your") shall mean an individual or Legal Entity exercising
23
+ permissions granted by this License.
24
+
25
+ "Source" form shall mean the preferred form for making modifications, including
26
+ but not limited to software source code, documentation source, and configuration
27
+ files.
28
+
29
+ "Object" form shall mean any form resulting from mechanical transformation or
30
+ translation of a Source form, including but not limited to compiled object code,
31
+ generated documentation, and conversions to other media types.
32
+
33
+ "Work" shall mean the work of authorship, whether in Source or Object form, made
34
+ available under the License, as indicated by a copyright notice that is included
35
+ in or attached to the work (an example is provided in the Appendix below).
36
+
37
+ "Derivative Works" shall mean any work, whether in Source or Object form, that
38
+ is based on (or derived from) the Work and for which the editorial revisions,
39
+ annotations, elaborations, or other modifications represent, as a whole, an
40
+ original work of authorship. For the purposes of this License, Derivative Works
41
+ shall not include works that remain separable from, or merely link (or bind by
42
+ name) to the interfaces of, the Work and Derivative Works thereof.
43
+
44
+ "Contribution" shall mean any work of authorship, including the original version
45
+ of the Work and any modifications or additions to that Work or Derivative Works
46
+ thereof, that is intentionally submitted to Licensor for inclusion in the Work
47
+ by the copyright owner or by an individual or Legal Entity authorized to submit
48
+ on behalf of the copyright owner. For the purposes of this definition,
49
+ "submitted" means any form of electronic, verbal, or written communication sent
50
+ to the Licensor or its representatives, including but not limited to
51
+ communication on electronic mailing lists, source code control systems, and
52
+ issue tracking systems that are managed by, or on behalf of, the Licensor for
53
+ the purpose of discussing and improving the Work, but excluding communication
54
+ that is conspicuously marked or otherwise designated in writing by the copyright
55
+ owner as "Not a Contribution."
56
+
57
+ "Contributor" shall mean Licensor and any individual or Legal Entity on behalf
58
+ of whom a Contribution has been received by Licensor and subsequently
59
+ incorporated within the Work.
60
+
61
+ 2. Grant of Copyright License.
62
+
63
+ Subject to the terms and conditions of this License, each Contributor hereby
64
+ grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
65
+ irrevocable copyright license to reproduce, prepare Derivative Works of,
66
+ publicly display, publicly perform, sublicense, and distribute the Work and such
67
+ Derivative Works in Source or Object form.
68
+
69
+ 3. Grant of Patent License.
70
+
71
+ Subject to the terms and conditions of this License, each Contributor hereby
72
+ grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
73
+ irrevocable (except as stated in this section) patent license to make, have
74
+ made, use, offer to sell, sell, import, and otherwise transfer the Work, where
75
+ such license applies only to those patent claims licensable by such Contributor
76
+ that are necessarily infringed by their Contribution(s) alone or by combination
77
+ of their Contribution(s) with the Work to which such Contribution(s) was
78
+ submitted. If You institute patent litigation against any entity (including a
79
+ cross-claim or counterclaim in a lawsuit) alleging that the Work or a
80
+ Contribution incorporated within the Work constitutes direct or contributory
81
+ patent infringement, then any patent licenses granted to You under this License
82
+ for that Work shall terminate as of the date such litigation is filed.
83
+
84
+ 4. Redistribution.
85
+
86
+ You may reproduce and distribute copies of the Work or Derivative Works thereof
87
+ in any medium, with or without modifications, and in Source or Object form,
88
+ provided that You meet the following conditions:
89
+
90
+ You must give any other recipients of the Work or Derivative Works a copy of
91
+ this License; and
92
+ You must cause any modified files to carry prominent notices stating that You
93
+ changed the files; and
94
+ You must retain, in the Source form of any Derivative Works that You distribute,
95
+ all copyright, patent, trademark, and attribution notices from the Source form
96
+ of the Work, excluding those notices that do not pertain to any part of the
97
+ Derivative Works; and
98
+ If the Work includes a "NOTICE" text file as part of its distribution, then any
99
+ Derivative Works that You distribute must include a readable copy of the
100
+ attribution notices contained within such NOTICE file, excluding those notices
101
+ that do not pertain to any part of the Derivative Works, in at least one of the
102
+ following places: within a NOTICE text file distributed as part of the
103
+ Derivative Works; within the Source form or documentation, if provided along
104
+ with the Derivative Works; or, within a display generated by the Derivative
105
+ Works, if and wherever such third-party notices normally appear. The contents of
106
+ the NOTICE file are for informational purposes only and do not modify the
107
+ License. You may add Your own attribution notices within Derivative Works that
108
+ You distribute, alongside or as an addendum to the NOTICE text from the Work,
109
+ provided that such additional attribution notices cannot be construed as
110
+ modifying the License.
111
+ You may add Your own copyright statement to Your modifications and may provide
112
+ additional or different license terms and conditions for use, reproduction, or
113
+ distribution of Your modifications, or for any such Derivative Works as a whole,
114
+ provided Your use, reproduction, and distribution of the Work otherwise complies
115
+ with the conditions stated in this License.
116
+
117
+ 5. Submission of Contributions.
118
+
119
+ Unless You explicitly state otherwise, any Contribution intentionally submitted
120
+ for inclusion in the Work by You to the Licensor shall be under the terms and
121
+ conditions of this License, without any additional terms or conditions.
122
+ Notwithstanding the above, nothing herein shall supersede or modify the terms of
123
+ any separate license agreement you may have executed with Licensor regarding
124
+ such Contributions.
125
+
126
+ 6. Trademarks.
127
+
128
+ This License does not grant permission to use the trade names, trademarks,
129
+ service marks, or product names of the Licensor, except as required for
130
+ reasonable and customary use in describing the origin of the Work and
131
+ reproducing the content of the NOTICE file.
132
+
133
+ 7. Disclaimer of Warranty.
134
+
135
+ Unless required by applicable law or agreed to in writing, Licensor provides the
136
+ Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
137
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
138
+ including, without limitation, any warranties or conditions of TITLE,
139
+ NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
140
+ solely responsible for determining the appropriateness of using or
141
+ redistributing the Work and assume any risks associated with Your exercise of
142
+ permissions under this License.
143
+
144
+ 8. Limitation of Liability.
145
+
146
+ In no event and under no legal theory, whether in tort (including negligence),
147
+ contract, or otherwise, unless required by applicable law (such as deliberate
148
+ and grossly negligent acts) or agreed to in writing, shall any Contributor be
149
+ liable to You for damages, including any direct, indirect, special, incidental,
150
+ or consequential damages of any character arising as a result of this License or
151
+ out of the use or inability to use the Work (including but not limited to
152
+ damages for loss of goodwill, work stoppage, computer failure or malfunction, or
153
+ any and all other commercial damages or losses), even if such Contributor has
154
+ been advised of the possibility of such damages.
155
+
156
+ 9. Accepting Warranty or Additional Liability.
157
+
158
+ While redistributing the Work or Derivative Works thereof, You may choose to
159
+ offer, and charge a fee for, acceptance of support, warranty, indemnity, or
160
+ other liability obligations and/or rights consistent with this License. However,
161
+ in accepting such obligations, You may act only on Your own behalf and on Your
162
+ sole responsibility, not on behalf of any other Contributor, and only if You
163
+ agree to indemnify, defend, and hold each Contributor harmless for any liability
164
+ incurred by, or claims asserted against, such Contributor by reason of your
165
+ accepting any such warranty or additional liability.
166
+
167
+ END OF TERMS AND CONDITIONS
168
+
169
+ APPENDIX: How to apply the Apache License to your work
170
+
171
+ To apply the Apache License to your work, attach the following boilerplate
172
+ notice, with the fields enclosed by brackets "[]" replaced with your own
173
+ identifying information. (Don't include the brackets!) The text should be
174
+ enclosed in the appropriate comment syntax for the file format. We also
175
+ recommend that a file or class name and description of purpose be included on
176
+ the same "printed page" as the copyright notice for easier identification within
177
+ third-party archives.
178
+
179
+ # Copyright 2013 Petr Chalupa <git@pitr.ch>
180
+ #
181
+ # Licensed under the Apache License, Version 2.0 (the "License");
182
+ # you may not use this file except in compliance with the License.
183
+ # You may obtain a copy of the License at
184
+ #
185
+ # http://www.apache.org/licenses/LICENSE-2.0
186
+ #
187
+ # Unless required by applicable law or agreed to in writing, software
188
+ # distributed under the License is distributed on an "AS IS" BASIS,
189
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
190
+ # See the License for the specific language governing permissions and
191
+ # limitations under the License.
data/README.md CHANGED
@@ -1,7 +1,55 @@
1
- ## Algebrick
1
+ # Algebrick
2
2
 
3
- Is a small gem providing algebraic types and pattern matching on them for Ruby.
3
+ [![Build Status](https://travis-ci.org/pitr-ch/algebrick.png?branch=master)](https://travis-ci.org/pitr-ch/algebrick)
4
+
5
+ It's a small gem providing **algebraic types** and **pattern matching** on them for Ruby.
4
6
 
5
7
  - Documentation: <http://blog.pitr.ch/algebrick>
6
8
  - Source: <https://github.com/pitr-ch/algebrick>
7
9
  - Blog: <http://blog.pitr.ch/blog/categories/algebrick/>
10
+
11
+ ## What is it good for?
12
+
13
+ - Defining data structures.
14
+ - Algebraic types play nice with JSON serialization and deserialization. It is ideal for defining
15
+ message-based cross-process communication.
16
+ - and more...
17
+
18
+ ## Quick example
19
+
20
+ Load DSL for type definition and define some algebraic types
21
+
22
+ ```ruby
23
+ extend Algebrick::DSL
24
+
25
+ type_def do
26
+ tree === empty | leaf(Integer) | node(tree, tree)
27
+ end
28
+ ```
29
+
30
+ Now types `Tree(Empty | Leaf | Node)`, `Empty`, `Leaf(Integer)` and `Node(Tree, Tree)` are defined.
31
+ Lets add some methods, don't miss the **pattern matching** example.
32
+
33
+ ```ruby
34
+ module Tree
35
+ # compute depth of a tree
36
+ def depth
37
+ match self,
38
+ Empty >> 0,
39
+ Leaf >> 1,
40
+ # ~ will store and pass matched parts to variables left and right
41
+ Node.(~any, ~any) --> left, right do
42
+ 1 + [left.depth, right.depth].max
43
+ end
44
+ end
45
+ end
46
+ ```
47
+
48
+ Methods are defined on **all** values of type Tree
49
+
50
+ ```ruby
51
+ Empty.depth # => 0
52
+ Leaf[10].depth # => 1
53
+ Node[Leaf[4], Empty].depth # => 2
54
+ Node[Empty, Node[Leaf[1], Empty]].depth # => 3
55
+ ```
data/README_FULL.md CHANGED
@@ -1,14 +1,14 @@
1
1
  # Algebrick
2
2
 
3
- Is a small gem providing algebraic types and pattern matching on them for Ruby.
3
+ Is a small gem providing **algebraic types** and **pattern matching** on them for Ruby.
4
4
 
5
5
  - Documentation: <http://blog.pitr.ch/algebrick>
6
6
  - Source: <https://github.com/pitr-ch/algebrick>
7
7
  - Blog: <http://blog.pitr.ch/blog/categories/algebrick/>
8
8
 
9
- ## Quick example with Maybe type
9
+ ## Quick example
10
10
 
11
- {include:file:doc/maybe.out.rb}
11
+ {include:file:doc/quick_example.out.rb}
12
12
 
13
13
  ## Algebraic types: what is it?
14
14
 
@@ -62,8 +62,8 @@ Algebraic matchers are helper objects to match algebraic objects and others with
62
62
 
63
63
  ### Serialization
64
64
 
65
- Algebraic types also play nice with JSON serialization. So it is ideal for defining messegas
66
- for cross-process comunication.
65
+ Algebraic types also play nice with JSON serialization and deserialization. It is ideal for defining
66
+ messege-based cross-process comunication.
67
67
 
68
68
  {include:file:doc/json.out.rb}
69
69
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.1.3
data/lib/algebrick.rb CHANGED
@@ -1,4 +1,20 @@
1
- # TODO method definition in variant type defines methods on variants based on match
1
+ # Copyright 2013 Petr Chalupa <git@pitr.ch>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
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
2
18
 
3
19
  require 'set'
4
20
 
@@ -18,9 +34,9 @@ module Algebrick
18
34
  end
19
35
 
20
36
  module TypeCheck
21
- #def is_kind_of?(value, *types)
22
- # a_type_check :kind_of?, false, value, *types
23
- #end
37
+ def is_kind_of?(value, *types)
38
+ a_type_check :kind_of?, false, value, *types
39
+ end
24
40
 
25
41
  def is_kind_of!(value, *types)
26
42
  a_type_check :kind_of?, true, value, *types
@@ -191,6 +207,9 @@ module Algebrick
191
207
  end
192
208
  end
193
209
 
210
+ TYPE_KEY = :algebrick
211
+ FIELDS_KEY = :fields
212
+
194
213
  class Atom < Type
195
214
  include Value
196
215
 
@@ -220,7 +239,7 @@ module Algebrick
220
239
  end
221
240
 
222
241
  def to_hash
223
- { name => name }
242
+ { TYPE_KEY => name }
224
243
  end
225
244
 
226
245
  def from_hash(hash)
@@ -263,12 +282,12 @@ module Algebrick
263
282
  end
264
283
 
265
284
  def to_hash
266
- { self.class.type.name =>
267
- if type.field_names
268
- type.field_names.inject({}) { |h, name| h.update name => hashize(self[name]) }
269
- else
270
- fields.map { |v| hashize v }
271
- end }
285
+ { TYPE_KEY => self.class.type.name }.
286
+ update(if type.field_names
287
+ type.field_names.inject({}) { |h, name| h.update name => hashize(self[name]) }
288
+ else
289
+ { FIELDS_KEY => fields.map { |v| hashize v } }
290
+ end)
272
291
  end
273
292
 
274
293
  def ==(other)
@@ -346,21 +365,13 @@ module Algebrick
346
365
  end
347
366
 
348
367
  def set_fields(fields_or_hash)
349
- fields = if fields_or_hash.size == 1 && fields_or_hash.first.is_a?(Hash)
350
- keys = fields_or_hash.first.keys
351
- fields_or_hash.first.values
352
- else
353
- fields_or_hash
354
- end
355
-
356
- if keys
357
- @field_names = keys
358
- keys.all? { |k| is_kind_of! k, Symbol }
359
- dict = @field_indexes =
360
- Hash.new { |h, k| raise ArgumentError, "uknown field #{k.inspect}" }.
361
- update keys.each_with_index.inject({}) { |h, (k, i)| h.update k => i }
362
- define_method(:[]) { |key| @fields[dict[key]] }
363
- end
368
+ fields, keys = if fields_or_hash.size == 1 && fields_or_hash.first.is_a?(Hash)
369
+ [fields_or_hash.first.values, fields_or_hash.first.keys]
370
+ else
371
+ [fields_or_hash, nil]
372
+ end
373
+
374
+ set_field_names keys if keys
364
375
 
365
376
  fields.all? { |f| is_kind_of! f, Type, Class }
366
377
  raise TypeError, 'there is no product with zero fields' unless fields.size > 0
@@ -369,6 +380,15 @@ module Algebrick
369
380
  @constructor = Class.new(ProductConstructor).tap { |c| c.type = self }
370
381
  end
371
382
 
383
+ def set_field_names(names)
384
+ @field_names = names
385
+ names.all? { |k| is_kind_of! k, Symbol }
386
+ dict = @field_indexes =
387
+ Hash.new { |h, k| raise ArgumentError, "uknown field #{k.inspect}" }.
388
+ update names.each_with_index.inject({}) { |h, (k, i)| h.update k => i }
389
+ define_method(:[]) { |key| @fields[dict[key]] }
390
+ end
391
+
372
392
  def set_variants(variants)
373
393
  variants.all? { |v| is_kind_of! v, Type, Class }
374
394
  @variants = variants
@@ -399,10 +419,14 @@ module Algebrick
399
419
  end
400
420
 
401
421
  def product_from_hash(hash)
402
- raise ArgumentError, 'hash does not have size 1' unless hash.size == 1
403
- type_name, fields = hash.first
422
+ (type_name = hash[TYPE_KEY] || hash[TYPE_KEY.to_s]) or
423
+ raise ArgumentError, "hash does not have #{TYPE_KEY}"
404
424
  raise ArgumentError, "#{type_name} is not #{name}" unless type_name == name
425
+
426
+ fields = hash[FIELDS_KEY] || hash[FIELDS_KEY.to_s] ||
427
+ hash.reject { |k, _| k.to_s == TYPE_KEY.to_s }
405
428
  is_kind_of! fields, Hash, Array
429
+
406
430
  case fields
407
431
  when Array
408
432
  self[*fields.map { |value| field_from_hash value }]
@@ -416,14 +440,9 @@ module Algebrick
416
440
 
417
441
  def field_from_hash(hash)
418
442
  return hash unless Hash === hash
419
- return hash unless hash.size == 1
420
- type_name, value = hash.first
421
- type = constantize type_name
422
- if type.respond_to? :from_hash
423
- type.from_hash hash
424
- else
425
- value
426
- end
443
+ (type_name = hash[TYPE_KEY] || hash[TYPE_KEY.to_s]) or return hash
444
+ type = constantize type_name
445
+ type.from_hash hash
427
446
  end
428
447
 
429
448
  def constantize(camel_cased_word)
@@ -446,10 +465,12 @@ module Algebrick
446
465
  super(&block)
447
466
  end
448
467
 
449
- def [](*fields)
468
+ def new(*fields)
450
469
  construct_product(*fields)
451
470
  end
452
471
 
472
+ alias_method :[], :new
473
+
453
474
  def be_kind_of!(type)
454
475
  product_be_kind_of type
455
476
  end
@@ -527,10 +548,12 @@ module Algebrick
527
548
  Matchers::Variant.new self
528
549
  end
529
550
 
530
- def [](*fields)
551
+ def new(*fields)
531
552
  construct_product(*fields)
532
553
  end
533
554
 
555
+ alias_method :[], :new
556
+
534
557
  def ==(other)
535
558
  other.kind_of? ProductVariant and
536
559
  variants == other.variants and fields == other.fields
@@ -951,7 +974,7 @@ module Algebrick
951
974
  Object
952
975
  else
953
976
  base
954
- end
977
+ end
955
978
  @pre_types = {}
956
979
  instance_eval &definition
957
980
  end
@@ -1010,8 +1033,8 @@ module Algebrick
1010
1033
 
1011
1034
  select.(ProductVariant) do |name, type, pre_type|
1012
1035
  type.send :initialize,
1013
- pre_type.fields.map { |f| get_class f },
1014
- pre_type.variants.map { |v| get_class v }
1036
+ pre_type.fields.map { |f| get_class f },
1037
+ pre_type.variants.map { |v| get_class v }
1015
1038
  end
1016
1039
  end
1017
1040
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: algebrick
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Petr Chalupa
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest-reporters
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: turn
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -67,7 +81,21 @@ dependencies:
67
81
  - !ruby/object:Gem::Version
68
82
  version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
- name: kramdown
84
+ name: redcarpet
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: github-markup
71
99
  requirement: !ruby/object:Gem::Requirement
72
100
  requirements:
73
101
  - - '>='
@@ -99,16 +127,16 @@ email: git@pitr.ch
99
127
  executables: []
100
128
  extensions: []
101
129
  extra_rdoc_files:
102
- - MIT-LICENSE
130
+ - LICENSE
103
131
  - README.md
104
132
  - README_FULL.md
133
+ - VERSION
105
134
  files:
106
135
  - lib/algebrick.rb
107
136
  - VERSION
108
- - MIT-LICENSE
137
+ - LICENSE
109
138
  - README.md
110
139
  - README_FULL.md
111
- - spec/algebrick.rb
112
140
  homepage: https://github.com/pitr-ch/algebrick
113
141
  licenses:
114
142
  - MIT
@@ -133,6 +161,5 @@ rubygems_version: 2.0.0
133
161
  signing_key:
134
162
  specification_version: 4
135
163
  summary: Algebraic types and pattern matching for Ruby
136
- test_files:
137
- - spec/algebrick.rb
164
+ test_files: []
138
165
  has_rdoc:
data/MIT-LICENSE DELETED
@@ -1,19 +0,0 @@
1
- Copyright (c) 2013 Petr Chalupa <git@pitr.ch>
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining a copy
4
- of this software and associated documentation files (the "Software"), to deal
5
- in the Software without restriction, including without limitation the rights
6
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- copies of the Software, and to permit persons to whom the Software is
8
- furnished to do so, subject to the following conditions:
9
-
10
- The above copyright notice and this permission notice shall be included in
11
- all copies or substantial portions of the Software.
12
-
13
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- THE SOFTWARE.
data/spec/algebrick.rb DELETED
@@ -1,541 +0,0 @@
1
- require 'bundler/setup'
2
-
3
- require 'minitest/spec'
4
- #require 'minitest/autorun'
5
- require 'turn/autorun'
6
-
7
- require 'pp'
8
- require_relative '../lib/algebrick'
9
- require 'pry'
10
-
11
- class Module
12
- def const_missing const
13
- raise "no constant #{const.inspect} in #{self}"
14
- end
15
- end
16
-
17
- Turn.config do |c|
18
- # use one of output formats:
19
- # :outline - turn's original case/test outline mode [default]
20
- # :progress - indicates progress with progress bar
21
- # :dotted - test/unit's traditional dot-progress mode
22
- # :pretty - new pretty reporter
23
- # :marshal - dump output as YAML (normal run mode only)
24
- # :cue - interactive testing
25
- c.format = :outline
26
- # turn on invoke/execute tracing, enable full backtrace
27
- #c.trace = true
28
- # use humanized test names (works only with :outline format)
29
- c.natural = true
30
- end
31
-
32
-
33
- describe 'AlgebrickTest' do
34
- i_suck_and_my_tests_are_order_dependent!
35
-
36
- #type_def do
37
- # maybe === none | some(Object)
38
-
39
- # message === success | failure
40
- # sucess === int(Integer) | str(String)
41
- # failure === error | str_error(String)
42
-
43
- #user = user(String, address) do
44
- # def name
45
- # fields[0]
46
- # end
47
- #
48
- # def address
49
- # fields[1]
50
- # end
51
- #end
52
- #
53
- #psc = psc(String) do
54
- # REG = /\d{5}/
55
- #
56
- # def initialize(*fields)
57
- # raise TypeError unless fields[0] =~ REG
58
- # end
59
- #
60
- # def schema
61
- # super << { pattern: REG.to_s }
62
- # end
63
- #end
64
- #
65
- ## street, num, city
66
- #address = address(street(String), street_number(Integer), city(String), psc)
67
- #
68
- #message1 === user
69
- #
70
- #User['pepa',
71
- # Adress[
72
- # Street['Stavebni'],
73
- # StreetNumber[5],
74
- # City['Brno']]]
75
- #
76
- #{ user: ['pepa',
77
- # { address: [{ street: 'Stavebni' },
78
- # { street_number: 5 }] }] }
79
-
80
- #sucess === int(Integer) | str(String)
81
- #failure === error | str_error(String)
82
- #message === success | failure
83
-
84
-
85
- #list === empty | list_item(Integer, list)
86
- #end
87
-
88
- #Empty = Algebrick::Atom.new
89
- #Leaf = Algebrick::Product.new(Integer)
90
- #Tree = Algebrick::Variant.allocate
91
- #Node = Algebrick::Product.new(Tree, Tree)
92
- #Tree.send :initialize, Empty, Leaf, Node do
93
- # def a
94
- # :a
95
- # end
96
- #end
97
- #List = Algebrick::ProductVariant.allocate
98
- #List.send :initialize, [Integer, List], [Empty, List]
99
-
100
- extend Algebrick::DSL
101
-
102
- type_def do
103
- tree === empty | leaf(Integer) | node(tree, tree)
104
- tree do
105
- def a
106
- :a
107
- end
108
-
109
- def depth
110
- case self
111
- when Empty
112
- 0
113
- when Leaf
114
- 1
115
- when Node
116
- left, right = *self
117
- 1 + [left.depth, right.depth].max
118
- end
119
- end
120
-
121
- def each(&block)
122
- return to_enum :each unless block
123
- case self
124
- when Empty
125
- when Leaf
126
- block.call self.value
127
- when Node
128
- left, right = *self
129
- left.each &block
130
- right.each &block
131
- end
132
- end
133
-
134
- def sum
135
- each.inject(0) { |sum, v| sum + v }
136
- end
137
- end
138
-
139
- list === empty | list(Integer, list)
140
- end
141
-
142
- Empty = self::Empty
143
- Node = self::Node
144
- Leaf = self::Leaf
145
- Tree = self::Tree
146
- List = self::List
147
-
148
- describe 'type definition' do
149
- module Asd
150
- Algebrick.type_def self do
151
- b === c | d
152
- end
153
- end
154
-
155
- it 'asd' do
156
- assert Asd::B
157
- end
158
- end
159
-
160
- describe 'type.to_s' do
161
- it { Empty.to_s.must_equal 'Empty' }
162
- it { Node.to_s.must_equal 'Node(Tree, Tree)' }
163
- it { Leaf.to_s.must_equal 'Leaf(Integer)' }
164
- it { Tree.to_s.must_equal 'Tree(Empty | Leaf | Node)' }
165
- it { List.to_s.must_equal 'List(Empty | List(Integer, List))' }
166
- end
167
-
168
- describe 'atom' do
169
- it { Empty.must_be_kind_of Algebrick::Type }
170
- it { Empty.must_be_kind_of Algebrick::Value }
171
- it { assert Empty.kind_of? Empty }
172
-
173
- it { assert Empty == Empty }
174
- it { assert Empty === Empty }
175
- it { eval(Empty.to_s).must_equal Empty }
176
- it { eval(Empty.inspect).must_equal Empty }
177
-
178
- it { Empty.from_hash(Empty.to_hash).must_equal Empty }
179
- end
180
-
181
- describe 'product' do
182
- it { Leaf[1].must_be_kind_of Algebrick::Value }
183
- it { Leaf.must_be_kind_of Algebrick::Type }
184
- it { Leaf[1].wont_be_kind_of Algebrick::Type }
185
- it { Leaf.wont_be_kind_of Algebrick::Value }
186
-
187
- it { assert Leaf[1] == Leaf[1] }
188
- it { assert Leaf[1] != Leaf[0] }
189
- it { assert Leaf === Leaf[1] }
190
- it { assert Leaf[1].kind_of? Leaf }
191
- it { eval(Leaf[1].to_s).must_equal Leaf[1] }
192
- it { eval(Leaf[1].inspect).must_equal Leaf[1] }
193
- it { eval(Node[Leaf[1], Empty].to_s).must_equal Node[Leaf[1], Empty] }
194
- it { eval(Node[Leaf[1], Empty].inspect).must_equal Node[Leaf[1], Empty] }
195
-
196
- it 'field assign' do
197
- value = Leaf[1].value
198
- value.must_equal 1
199
-
200
- left, right = *Node[Empty, Leaf[1]]
201
- left.must_equal Empty
202
- right.must_equal Leaf[1]
203
-
204
- lambda { Node[Empty, Empty].value }.must_raise NoMethodError
205
- end
206
-
207
- it { lambda { Leaf['a'] }.must_raise TypeError }
208
- it { lambda { Leaf[nil] }.must_raise TypeError }
209
- it { lambda { Node['a'] }.must_raise TypeError }
210
- it { lambda { Node[Empty, nil] }.must_raise TypeError }
211
-
212
- describe 'named field' do
213
- type_def { named(a: Integer, b: Object) }
214
- Named = self::Named
215
- Named.add_all_field_method_accessors
216
- it { -> { Named[:a, 1] }.must_raise TypeError }
217
- it { Named[1, :a][:a].must_equal 1 }
218
- it { Named[1, :a][:b].must_equal :a }
219
- it { Named[a: 1, b: :a][:a].must_equal 1 }
220
- it { Named[b: :a, a: 1][:a].must_equal 1 }
221
- it { Named[a: 1, b: :a][:b].must_equal :a }
222
- it { Named[a: 1, b: 2].to_s.must_equal 'Named[a: 1, b: 2]' }
223
- it { Named[a: 1, b: 2].a.must_equal 1 }
224
- it { Named[a: 1, b: 2].b.must_equal 2 }
225
- end
226
-
227
- it { Leaf.from_hash(Leaf[1].to_hash).must_equal Leaf[1] }
228
- it { Named.from_hash(Named[1, :a].to_hash).must_equal Named[1, :a] }
229
- it { Named[1, Leaf[1]].to_hash.must_equal 'Named' => { a: 1, b: { 'Leaf' => [1] } } }
230
- it { Named.from_hash(Named[1, Leaf[1]].to_hash).must_equal Named[1, Leaf[1]] }
231
-
232
- end
233
-
234
- describe 'variant' do
235
- it { Tree.must_be_kind_of Algebrick::Type }
236
- it { Empty.must_be_kind_of Tree }
237
- it { Empty.a.must_equal :a }
238
- it { Leaf[1].must_be_kind_of Tree }
239
- it { Leaf[1].a.must_equal :a }
240
- it { Node[Empty, Empty].must_be_kind_of Tree }
241
- #it { assert Empty.kind_of? List }
242
-
243
- it { assert Tree === Empty }
244
- it { assert Tree === Leaf[1] }
245
-
246
- describe 'inherit behavior deep' do
247
- type_def do
248
- a === a1 | a2
249
- a1 === b1 | b2
250
- a do
251
- def a
252
- :a
253
- end
254
- end
255
- end
256
-
257
- it { self.class::B1.a.must_equal :a }
258
- end
259
-
260
- describe 'a klass as a variant' do
261
- MaybeString = Algebrick::Variant.new Empty, String
262
- it { 'a'.must_be_kind_of MaybeString }
263
- end
264
- end
265
-
266
- describe 'product_variant' do
267
- it { List[1, Empty].must_be_kind_of Algebrick::Value }
268
- it { List.must_be_kind_of Algebrick::Type }
269
-
270
- it { List[1, Empty].must_be_kind_of List }
271
- it { List[1, List[1, Empty]].must_be_kind_of List }
272
- it { Empty.must_be_kind_of List }
273
-
274
- it { assert List[1, Empty] == List[1, Empty] }
275
- it { assert List[1, Empty] != List[2, Empty] }
276
- it { assert List === List[1, Empty] }
277
- it { assert List === Empty }
278
- it { assert List[1, Empty].kind_of? List }
279
- end
280
-
281
- describe '#depth' do
282
- it do
283
- tree = Node[Node[Empty, Leaf[1]], Leaf[1]]
284
- tree.depth.must_equal 3
285
- end
286
- it do
287
- tree = Node[Empty, Leaf[1]]
288
- tree.depth.must_equal 2
289
- end
290
- it do
291
- tree = Empty
292
- tree.depth.must_equal 0
293
- end
294
- end
295
-
296
- describe '#sum' do
297
- it do
298
- tree = Node[Node[Empty, Leaf[1]], Leaf[1]]
299
- tree.sum.must_equal 2
300
- end
301
- end
302
-
303
- describe 'maybe' do
304
- type_def do
305
- maybe === none | some(Object)
306
- maybe do
307
- def maybe(&block)
308
- case self
309
- when None
310
- when Some
311
- block.call self.value
312
- end
313
- end
314
- end
315
- end
316
-
317
- None = self::None
318
- Some = self::Some
319
-
320
- it { refute None.maybe { true } }
321
- it { assert Some[nil].maybe { true } }
322
- end
323
-
324
- extend Algebrick::Matching
325
- include Algebrick::Matching
326
-
327
- describe 'matchers' do
328
- it 'assigns' do
329
- m = ~Empty
330
- m === 2
331
- m.assigns.must_equal [nil]
332
- m === Empty
333
- m.assigns.must_equal [Empty]
334
-
335
- m = ~String.to_m
336
- m === 2
337
- m.assigns.must_equal [nil]
338
- m === 'a'
339
- m.assigns.must_equal %w(a)
340
-
341
- m = ~Leaf.(~any)
342
- m === Leaf[5]
343
- m.assigns.must_equal [Leaf[5], 5]
344
- m === Leaf[3]
345
- m.assigns.must_equal [Leaf[3], 3]
346
- end
347
-
348
- it 'assigns in case' do
349
- case Leaf[5]
350
- when m = ~Leaf.(~any)
351
- m.assigns.must_equal [Leaf[5], 5]
352
- m.assigns do |leaf, value|
353
- leaf.must_equal Leaf[5]
354
- value.must_equal 5
355
- end
356
- else
357
- raise
358
- end
359
- end
360
-
361
- describe 'match' do
362
- it 'returns value from executed block' do
363
- Algebrick.match(Empty, Empty.to_m.case { 1 }).must_equal 1
364
- end
365
-
366
- it 'passes assigned values' do
367
- v = Algebrick.match Leaf[5],
368
- Leaf.(~any).case { |value| value }
369
- v.must_equal 5
370
-
371
- v = Algebrick.match Leaf[5],
372
- Leaf.(~any) => -> value { value }
373
- v.must_equal 5
374
- end
375
-
376
- it 'raises when no match' do
377
- -> { Algebrick.match Empty,
378
- Leaf.(any).case {} }.must_raise RuntimeError
379
- end
380
-
381
- it 'does not pass any values when no matcher' do
382
- Algebrick.match(Empty, Empty => -> *a { a }).must_equal []
383
- end
384
- end
385
-
386
- describe '#to_s' do
387
- [Empty.to_m,
388
- # leaf(Object)
389
- ~Leaf.(Integer),
390
- ~Empty.to_m,
391
- any,
392
- ~any,
393
- Leaf.(any),
394
- ~Leaf.(any),
395
- Node.(Leaf.(any), any),
396
- ~Node.(Leaf.(any), any),
397
- ~Leaf.(1) | Leaf.(~any),
398
- ~Leaf.(1) & Leaf.(~any)
399
- ].each do |matcher|
400
- it matcher.to_s do
401
- eval(matcher.to_s).must_equal matcher
402
- end
403
- end
404
- end
405
-
406
- { Empty.to_m => Empty,
407
- any => Empty,
408
- any => Leaf[1],
409
-
410
- Empty => Empty,
411
- Empty.to_m => Empty,
412
-
413
- Leaf => Leaf[1],
414
- Leaf.(any) => Leaf[5],
415
- Leaf.(~any) => Leaf[5],
416
-
417
- Node => Node[Empty, Empty],
418
- Node.(any, any) => Node[Leaf[1], Empty],
419
- Node.(Empty, any) => Node[Empty, Leaf[1]],
420
- Node.(Leaf.(any), any) => Node[Leaf[1], Empty],
421
- Node.(Leaf.(any), any) => Node[Leaf[1], Empty],
422
-
423
- Tree.to_m => Node[Leaf[1], Empty],
424
- Tree.to_m => Node[Leaf[1], Empty],
425
- Node => Node[Leaf[1], Empty],
426
-
427
- Tree & Leaf.(_) => Leaf[1],
428
- Empty | Leaf.(_) => Leaf[1],
429
- Empty | Leaf.(_) => Empty,
430
- !Empty & Leaf.(_) => Leaf[1],
431
- Empty & !Leaf.(_) => Empty,
432
-
433
- Array.() => [],
434
- Array.(1) => [1],
435
- Array.(Empty, Leaf.(-> v { v > 0 })) => [Empty, Leaf[1]],
436
- Array.(TrueClass) => [true],
437
-
438
- }.each do |matcher, value|
439
- it "#{matcher} === #{value}" do
440
- assert matcher === value
441
- end
442
- end
443
- end
444
-
445
- it {
446
- assert List.to_m === Empty
447
- assert List === Empty
448
- assert List.to_m === List[1, Empty]
449
- assert List === List[1, Empty]
450
- assert List.(1, _) === List[1, Empty]
451
- refute List.(_, _) === Empty
452
- }
453
-
454
- describe 'and-or matching' do
455
- it do
456
- m = ~Leaf.(1) | ~Leaf.(~any)
457
- assert m === Leaf[1]
458
- m.assigns.must_equal [Leaf[1], nil, nil]
459
- end
460
- it do
461
- m = ~Leaf.(1) | ~Leaf.(~any)
462
- assert m === Leaf[2]
463
- m.assigns.must_equal [nil, Leaf[2], 2]
464
- end
465
- it do
466
- m = ~Leaf.(->(v) { v > 1 }) & Leaf.(~any)
467
- assert m === Leaf[2]
468
- m.assigns.must_equal [Leaf[2], 2]
469
- end
470
-
471
- end
472
-
473
- describe 'equality' do
474
- data = (0..1).map do
475
- [Empty,
476
- Leaf[1],
477
- Node[Empty, Leaf[1]],
478
- Node[Node[Empty, Leaf[1]], Leaf[1]]]
479
- end
480
- data[0].zip(data[1]).each do |tree1, tree2|
481
- it "equals #{tree1}" do
482
- refute tree1.object_id == tree2.object_id, [tree1.object_id, tree2.object_id] unless tree1 == Empty
483
- assert tree1 == tree2
484
- end
485
- end
486
- end
487
-
488
- describe 'list' do
489
- it { List.(any, any) === List[1, Empty] }
490
- it { List.(any, List) === List[1, Empty] }
491
- end
492
-
493
- describe 'binary tree' do
494
- type_def { b_tree === tip | b_node(Object, b_tree, b_tree) }
495
- end
496
-
497
- end
498
-
499
-
500
- #require 'benchmark'
501
- #
502
- #include Algebrick
503
- #
504
- #class None < Atom
505
- #end
506
- #
507
- #class Some < Product
508
- # fields Object
509
- #end
510
- #
511
- #Maybe = Variant.new do
512
- # variants None, Some
513
- #end
514
- #count = 1000_000
515
- #
516
- #Benchmark.bmbm(10) do |b|
517
- # b.report('nil') do
518
- # count.times do
519
- # v = [Object.new, nil].sample
520
- # case v
521
- # when Object
522
- # true
523
- # when nil
524
- # false
525
- # end
526
- # end
527
- # end
528
- # b.report('Maybe') do
529
- # count.times do
530
- # v = [Some[Object.new], None].sample
531
- # case v
532
- # when Some
533
- # true
534
- # when Maybe
535
- # false
536
- # end
537
- # end
538
- # end
539
- #
540
- #
541
- #end