algebrick 0.7.3 → 0.7.4

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: acb97762ca9adaf44bcddd29fd57985f77c0d98c
4
- data.tar.gz: 67a118f7462a29d4d29edeeff5cf1ce4c9a4b259
3
+ metadata.gz: 031ca75f438646afcde4c41e4ab4e3b5db005f2e
4
+ data.tar.gz: 877ecd44cd33213e95f0a9bff41eb13f9300b45b
5
5
  SHA512:
6
- metadata.gz: 84402aff0bf09c611f7853ec255b97bdae86a7d43297a412a5d8f1d3aee8ef9c82303a233465b1e22a17f75f7fc2c693ebb3db9d4c194b54952c37941b59a1dc
7
- data.tar.gz: c4250f16434da8d17ce1ca866c1e549694f3960bc9d81a102ff65d908f4f450e69dbe5379c8708028d013d9c0fc49d19981ad05346eeb1084a44a01da4b1979b
6
+ metadata.gz: 1401bf9922ffd3a3cf6c66b215c249e8b0adb910c7f5325debe0158aef55b4d75c1b0020b26fa563372e5e5cd96b2e97be93418b72358138014215f5643a0440
7
+ data.tar.gz: c034a72430b4ba328b180068c70a0fe5a661f01a80ca8cfcb09808b8df821b013847a15aadd166c3576abfe411e07b84ddbd5131863d8f274d34773a7ad7bf91
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.3
1
+ 0.7.4
@@ -70,9 +70,9 @@ module Algebrick
70
70
  end
71
71
 
72
72
  def assigns
73
- collect_assigns.tap do
74
- return yield *assigns if block_given?
75
- end
73
+ assigns = collect_assigns
74
+ return yield *assigns if block_given?
75
+ assigns
76
76
  end
77
77
 
78
78
  def to_a
@@ -39,6 +39,12 @@ module Algebrick
39
39
  @fields == other.fields
40
40
  end
41
41
 
42
+ alias_method :eql?, :==
43
+
44
+ def hash
45
+ [self.class, @fields].hash
46
+ end
47
+
42
48
  def self.type
43
49
  @type || raise
44
50
  end
@@ -17,14 +17,19 @@ module Algebrick
17
17
  #noinspection RubySuperCallWithoutSuperclassInspection
18
18
  module Reclude
19
19
  def included(base)
20
- included_into << base
20
+ used_by << base
21
+ super(base)
22
+ end
23
+
24
+ def extended(base)
25
+ used_by << base
21
26
  super(base)
22
27
  end
23
28
 
24
29
  def include(*modules)
25
30
  super(*modules)
26
31
  modules.reverse.each do |module_being_included|
27
- included_into.each do |mod|
32
+ used_by.each do |mod|
28
33
  mod.send :include, module_being_included
29
34
  end
30
35
  end
@@ -32,8 +37,8 @@ module Algebrick
32
37
 
33
38
  private
34
39
 
35
- def included_into
36
- @included_into ||= []
40
+ def used_by
41
+ @used_by ||= []
37
42
  end
38
43
  end
39
44
  end
metadata CHANGED
@@ -1,43 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: algebrick
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.3
4
+ version: 0.7.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Petr Chalupa
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-02 00:00:00.000000000 Z
11
+ date: 2017-01-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '5.10'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: '5.10'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: minitest-reporters
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '1.1'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: '1.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: yard
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.9'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.9'
55
+ - !ruby/object:Gem::Dependency
56
+ name: kramdown
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.13'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.13'
41
69
  description: Provides algebraic type definitions and pattern matching
42
70
  email: git+algebrick@pitr.ch
43
71
  executables: []
@@ -47,56 +75,30 @@ extra_rdoc_files:
47
75
  - README.md
48
76
  - README_FULL.md
49
77
  - VERSION
50
- - doc/actor.rb
51
- - doc/data.in.rb
52
78
  - doc/data.out.rb
53
- - doc/extending_behavior.in.rb
54
79
  - doc/extending_behavior.out.rb
55
- - doc/format.rb
56
- - doc/init.rb
57
- - doc/json.in.rb
58
80
  - doc/json.out.rb
59
- - doc/null.in.rb
60
81
  - doc/null.out.rb
61
- - doc/parametrized.in.rb
62
82
  - doc/parametrized.out.rb
63
- - doc/pattern_matching.in.rb
64
83
  - doc/pattern_matching.out.rb
65
- - doc/quick_example.in.rb
66
84
  - doc/quick_example.out.rb
67
- - doc/tree1.in.rb
68
85
  - doc/tree1.out.rb
69
- - doc/type_def.in.rb
70
86
  - doc/type_def.out.rb
71
- - doc/values.in.rb
72
87
  - doc/values.out.rb
73
88
  files:
74
89
  - LICENSE.txt
75
90
  - README.md
76
91
  - README_FULL.md
77
92
  - VERSION
78
- - doc/actor.rb
79
- - doc/data.in.rb
80
93
  - doc/data.out.rb
81
- - doc/extending_behavior.in.rb
82
94
  - doc/extending_behavior.out.rb
83
- - doc/format.rb
84
- - doc/init.rb
85
- - doc/json.in.rb
86
95
  - doc/json.out.rb
87
- - doc/null.in.rb
88
96
  - doc/null.out.rb
89
- - doc/parametrized.in.rb
90
97
  - doc/parametrized.out.rb
91
- - doc/pattern_matching.in.rb
92
98
  - doc/pattern_matching.out.rb
93
- - doc/quick_example.in.rb
94
99
  - doc/quick_example.out.rb
95
- - doc/tree1.in.rb
96
100
  - doc/tree1.out.rb
97
- - doc/type_def.in.rb
98
101
  - doc/type_def.out.rb
99
- - doc/values.in.rb
100
102
  - doc/values.out.rb
101
103
  - lib/algebrick.rb
102
104
  - lib/algebrick/atom.rb
@@ -132,7 +134,7 @@ files:
132
134
  - lib/algebrick/value.rb
133
135
  homepage: https://github.com/pitr-ch/algebrick
134
136
  licenses:
135
- - Apache License 2.0
137
+ - Apache-2.0
136
138
  metadata: {}
137
139
  post_install_message:
138
140
  rdoc_options: []
@@ -150,9 +152,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
150
152
  version: '0'
151
153
  requirements: []
152
154
  rubyforge_project:
153
- rubygems_version: 2.4.5
155
+ rubygems_version: 2.5.1
154
156
  signing_key:
155
157
  specification_version: 4
156
158
  summary: Algebraic types and pattern matching for Ruby
157
159
  test_files: []
158
- has_rdoc:
@@ -1,21 +0,0 @@
1
- Work = Algebrick.type do
2
- fields key: String, work: Proc
3
- end
4
-
5
- Finished = Algebrick.type do
6
- fields key: String, result: Object, worker: Worker
7
- end
8
-
9
- class Worker < AbstractActor
10
- def initialize(executor)
11
- super()
12
- @executor = executor
13
- end
14
-
15
- def on_message(message)
16
- match message,
17
- Work.(~any, ~any) >-> key, work do
18
- @executor.tell Finished[key, work.call, self]
19
- end
20
- end
21
- end
@@ -1,99 +0,0 @@
1
- extend Algebrick::Matching
2
-
3
- # Simple data structures like trees
4
- Tree = Algebrick.type do |tree|
5
- variants Tip = type,
6
- Node = type { fields value: Object, left: tree, right: tree }
7
- end
8
-
9
- module Tree
10
- def depth
11
- match self,
12
- Tip.to_m >> 0,
13
- Node.(any, ~any, ~any) >-> left, right do
14
- 1 + [left.depth, right.depth].max
15
- end
16
- end
17
- end #
18
-
19
- tree = Node[2,
20
- Tip,
21
- Node[5,
22
- Node[4, Tip, Tip],
23
- Node[6, Tip, Tip]]]
24
- tree.depth
25
-
26
- # Whenever you find yourself to pass around too many fragile Hash-Array structures
27
- # e.g. for menus.
28
- Menu = Algebrick.type do |menu|
29
- Item = Algebrick.type do
30
- variants Delimiter = atom,
31
- Link = type { fields! label: String, url: String },
32
- Group = type { fields! label: String, submenu: menu }
33
- end
34
-
35
- fields! item: Item, next: menu
36
- variants None = atom, menu
37
- end
38
- None
39
- Item
40
-
41
- module Link
42
- def self.new(*fields)
43
- super(*fields).tap { |menu| valid! menu.url }
44
- end
45
-
46
- def self.valid!(url)
47
- # stub
48
- end
49
- end #
50
-
51
- module Item
52
- def draw_menu(indent = 0)
53
- match self,
54
- Delimiter >-> { [' '*indent + '-'*10] },
55
- Link.(label: ~any) >-> label { [' '*indent + label] },
56
- (on ~Group do |(label, sub_menu)|
57
- [' '*indent + label] + sub_menu.draw_menu(indent + 2)
58
- end)
59
- end
60
- end #
61
-
62
- module Menu
63
- def self.build(*items)
64
- items.reverse_each.reduce(None) { |menu, item| Menu[item, menu] }
65
- end
66
-
67
- include Enumerable
68
-
69
- def each(&block)
70
- it = self
71
- loop do
72
- break if None === it
73
- block.call it.item
74
- it = it.next
75
- end
76
- end
77
-
78
- def draw_menu(indent = 0)
79
- map { |item| item.draw_menu indent }.reduce(&:+)
80
- end
81
- end #
82
-
83
- sub_menu = Menu.build Link['Red Hat', '#red-hat'],
84
- Delimiter,
85
- Link['Ubuntu', '#ubuntu'],
86
- Link['Mint', '#mint']
87
-
88
- menu = Menu.build Link['Home', '#home'],
89
- Delimiter,
90
- Group['Linux', sub_menu],
91
- Link['About', '#about']
92
-
93
- menu.draw_menu.join("\n")
94
-
95
-
96
- # Group['Products',
97
- # Menu[]],
98
- # Link['About', '#about']
99
- #]]
@@ -1,61 +0,0 @@
1
- Maybe = Algebrick.type do
2
- variants None = atom,
3
- Some = type { fields Object }
4
- end
5
-
6
- # Types can be extended with usual syntax for modules and using Ruby supports module reopening.
7
- module Maybe
8
- def maybe(&block)
9
- case self
10
- when None
11
- when Some
12
- block.call value
13
- end
14
- end
15
- end #
16
-
17
- # #maybe method is defined on both values (None, Some) of Maybe.
18
- None.maybe { |_| raise 'never ever happens' }
19
- # Block is called with the value.
20
- Some[1].maybe { |v| v*2 }
21
-
22
- # It also works as expected when modules like Comparable are included.
23
- Season = Algebrick.type do
24
- variants Spring = atom,
25
- Summer = atom,
26
- Autumn = atom,
27
- Winter = atom
28
- end
29
-
30
- module Season
31
- include Comparable
32
- ORDER = Season.variants.each_with_index.each_with_object({}) { |(season, i), h| h[season] = i }
33
-
34
- def <=>(other)
35
- Type! other, Season
36
- ORDER[self] <=> ORDER[other]
37
- end
38
- end #
39
-
40
- Quarter = Algebrick.type do
41
- fields! year: Integer, season: Season
42
- end
43
-
44
- module Quarter
45
- include Comparable
46
-
47
- def <=>(other)
48
- Type! other, Quarter
49
- [year, season] <=> [other.year, other.season]
50
- end
51
- end #
52
-
53
- # Now Quarters and Seasons can be compared as expected.
54
- [Winter, Summer, Spring, Autumn].sort
55
- Quarter[2013, Spring] < Quarter[2013, Summer]
56
- Quarter[2014, Spring] > Quarter[2013, Summer]
57
- Quarter[2014, Spring] == Quarter[2014, Spring]
58
- [Quarter[2013, Spring], Quarter[2013, Summer], Quarter[2014, Spring]].sort
59
-
60
-
61
-
@@ -1,76 +0,0 @@
1
- require 'rubygems'
2
- require 'bundler/setup'
3
- require 'pry'
4
- require 'pp'
5
-
6
- root = File.dirname(File.expand_path(Process.argv0))
7
- input_paths = if ARGV.empty?
8
- Dir.glob("#{root}/*.in.rb")
9
- else
10
- ARGV
11
- end.map { |p| File.expand_path p }
12
-
13
- input_paths.each_with_index do |input_path, i|
14
-
15
- pid = fork do
16
- require File.join(root, 'init.rb')
17
-
18
- begin
19
- output_path = input_path.gsub /\.in\.rb$/, '.out.rb'
20
- input = File.readlines(input_path)
21
-
22
- chunks = []
23
- line = ''
24
-
25
- while !input.empty?
26
- line += input.shift
27
- if Pry::Code.complete_expression? line
28
- chunks << line
29
- line = ''
30
- end
31
- end
32
-
33
- raise unless line.empty?
34
-
35
- chunks.map! { |chunk| [chunk, [chunk.split($/).size, 1].max] }
36
- environment = Module.new.send :binding
37
- evaluate = ->(code, line) do
38
- eval(code, environment, input_path, line)
39
- end
40
-
41
- indent = 50
42
-
43
- line_count = 1
44
- output = ''
45
- chunks.each do |chunk, lines|
46
- result = evaluate.(chunk, line_count)
47
- unless chunk.strip.empty? || chunk =~ /\A *#/
48
- pre_lines = chunk.lines.to_a
49
- last_line = pre_lines.pop
50
- output << pre_lines.join
51
-
52
- if last_line =~ /\#$/
53
- output << last_line.gsub(/\#$/, '')
54
- else
55
- if last_line.size < indent && result.inspect.size < indent
56
- output << "%-#{indent}s %s" % [last_line.chomp, "# => #{result.inspect}\n"]
57
- else
58
- output << last_line << " # => #{result.inspect}\n"
59
- end
60
- end
61
- else
62
- output << chunk
63
- end
64
- line_count += lines
65
- end
66
-
67
- puts "#{input_path}\n -> #{output_path}"
68
- #puts output
69
- File.write(output_path, output)
70
- rescue => ex
71
- puts "#{ex} (#{ex.class})\n#{ex.backtrace * "\n"}"
72
- end
73
- end
74
-
75
- Process.wait pid
76
- end
@@ -1 +0,0 @@
1
- require 'algebrick'
@@ -1,39 +0,0 @@
1
- extend Algebrick::Matching
2
-
3
- # Lets define message-protocol for a cross-process communication.
4
- Request = Algebrick.type do
5
- User = type { fields login: String, password: String }
6
-
7
- variants CreateUser = type { fields User },
8
- GetUser = type { fields login: String }
9
- end
10
-
11
- Response = Algebrick.type do
12
- variants Success = type { fields Object },
13
- Failure = type { fields error: String }
14
- end
15
-
16
- Message = Algebrick.type { variants Request, Response }
17
-
18
- require 'algebrick/serializer'
19
- require 'multi_json'
20
-
21
- # Prepare a message for sending.
22
- serializer = Algebrick::Serializer.new
23
- request = CreateUser[User['root', 'lajDh4']]
24
- raw_request = MultiJson.dump serializer.dump(request)
25
-
26
- # Receive the message.
27
- response = match serializer.load(MultiJson.load(raw_request)),
28
- (on CreateUser.(~any) do |user|
29
- # create the user and send success
30
- Success[user]
31
- end)
32
-
33
- # Send response.
34
- response_raw = MultiJson.dump serializer.dump(response)
35
-
36
- # Receive response.
37
- serializer.load(MultiJson.load(response_raw))
38
-
39
-
@@ -1,36 +0,0 @@
1
- extend Algebrick::Matching
2
-
3
- def deliver_email(email)
4
- true
5
- end #
6
-
7
- Contact = Algebrick.type do |contact|
8
- variants Null = atom,
9
- contact
10
- fields username: String, email: String
11
- end
12
-
13
- module Contact
14
- def username
15
- match self,
16
- Null >> 'no name',
17
- Contact >-> { self[:username] }
18
- end
19
- def email
20
- match self,
21
- Null >> 'no email',
22
- Contact >-> { self[:email] }
23
- end
24
- def deliver_personalized_email
25
- match self,
26
- Null >> true,
27
- Contact >-> { deliver_email(self.email) }
28
- end
29
- end #
30
-
31
- peter = Contact['peter', 'example@dot.com']
32
- john = Contact[username: 'peter', email: 'example@dot.com']
33
- nobody = Null
34
-
35
- [peter, john, nobody].map &:email
36
- [peter, john, nobody].map &:deliver_personalized_email
@@ -1,37 +0,0 @@
1
- # Let's define Tree but this time parameterized by :value_type,
2
- Tree = Algebrick.type(:value_type) do |tree|
3
- variants Empty = atom,
4
- Leaf = type(:value_type) { fields value: :value_type },
5
- Node = type(:value_type) { fields left: tree, right: tree }
6
- end
7
-
8
- # with method depth defined as before.
9
- module Tree
10
- def depth
11
- match self,
12
- Empty >> 0,
13
- Leaf >> 1,
14
- Node.(~any, ~any) >-> left, right do
15
- 1 + [left.depth, right.depth].max
16
- end
17
- end
18
- end #
19
-
20
- # Then Tree, Leaf, Node are
21
- Tree.class
22
- [Tree, Leaf, Node]
23
- # which servers as factories to actual types.
24
- Tree[Float]
25
- Tree[String]
26
-
27
- # Types cannot be mixed.
28
- Leaf[Integer]['1'] rescue $!
29
- Node[Integer][Leaf[String]['a'], Empty] rescue $!
30
- Leaf[String]['1']
31
-
32
- # Depth method works as before.
33
- integer_tree = Node[Integer][Leaf[Integer][2], Empty]
34
- integer_tree.depth
35
- string_tree = Node[String][Empty, Empty]
36
- string_tree.depth
37
-
@@ -1,144 +0,0 @@
1
- # Let's define a tree and binary tree to demonstrate the pattern matching abilities.
2
- Tree = Algebrick.type do |tree|
3
- variants Empty = type,
4
- Leaf = type { fields Integer },
5
- Node = type { fields tree, tree }
6
- end
7
-
8
- BinaryTree = BTree = Algebrick.type do |btree|
9
- fields! value: Comparable, left: btree, right: btree
10
- variants Empty, btree
11
- end
12
-
13
- extend Algebrick::Matching
14
-
15
- # Product matchers are constructed with #.() syntax.
16
- Leaf.(any) === Leaf[1]
17
- Leaf.(1) === Leaf[1]
18
- Leaf.(2) === Leaf[1]
19
- # There are also some shortcuts to use when product has more fields.
20
- BTree.()
21
- BTree.(value: any, left: Empty)
22
- BTree.(value: any, left: Empty) === BTree[1, Empty, Empty]
23
-
24
- # Any object responding to #=== can be converted to matcher.
25
- (1..2).to_m
26
- (1..2).to_m === 2
27
- Empty.to_m
28
- # As matchers are using standard #=== method it does not have to be always converted.
29
- Empty === Empty
30
- Leaf === Leaf[1]
31
-
32
- # Tree matches all its values.
33
- [Empty, Leaf[1], Node[Empty, Empty]].all? { |v| Tree === v }
34
-
35
- # There is also a #match method in Matching module to make pattern matching easier.
36
- match Leaf[1], # supply the value for matching
37
- # if Leaf.(0) matches :zero is returned
38
- (on Leaf.(0), :zero),
39
- # when computation of the result needs to be avoided use block
40
- # if Leaf.(1) matches block is called and its result is returned
41
- (on Leaf.(1) do
42
- (1..10000).inject(:*) # expensive computation
43
- :one # which is :one in this case
44
- end)
45
-
46
- # Alternatively case can be used.
47
- case Leaf[1]
48
- when Leaf.(0)
49
- :zero
50
- when Leaf.(1)
51
- (1..10000).inject(:*) # expensive computation
52
- :one
53
- end
54
-
55
- # But that won't work nicely with value deconstruction.
56
- # Each matcher can be marked with #~ method to store value against which is being matched,
57
- # each matched value is passed to the block, ...
58
- match Leaf[0],
59
- (on ~Leaf.(~any) do |leaf, value|
60
- [leaf, value]
61
- end)
62
-
63
- btree = BTree[1,
64
- BTree[0, Empty, Empty],
65
- Empty]
66
- match btree,
67
- (on BTree.(any, ~any, ~any) do |left, right|
68
- [left, right]
69
- end)
70
-
71
- # or alternatively you can use Ruby's multi-assignment feature.
72
- match btree,
73
- (on ~BTree do |(_, left, right)|
74
- [left, right]
75
- end)
76
-
77
-
78
- # Matchers also support logical operations #& for and, #| for or, and #! for negation.
79
- Color = Algebrick.type do
80
- variants Black = atom,
81
- White = atom,
82
- Pink = atom,
83
- Grey = type { fields scale: Float }
84
- end
85
-
86
- def color?(color)
87
- match color,
88
- on(Black | Grey.(-> v { v < 0.2 }), 'black-ish'),
89
- on(White | Grey.(-> v { v > 0.8 }), 'white-ish'),
90
- on(Grey.(-> v { v >= 0.2 }) & Grey.(-> v { v <= 0.8 }), 'grey-ish'),
91
- on(Pink, "that's not a color ;)")
92
- end
93
-
94
- color? Black
95
- color? Grey[0.1]
96
- color? Grey[0.3]
97
- color? Grey[0.9]
98
- color? White
99
- color? Pink
100
-
101
- # A more complicated example of extracting node's value and values of its left and right side
102
- # using also logical operators to allow Empty sides.
103
- match BTree[0, Empty, BTree[1, Empty, Empty]],
104
- (on BTree.({ value: ~any,
105
- left: Empty | BTree.(value: ~any),
106
- right: Empty | BTree.(value: ~any) }) do |value, left, right|
107
- { left: left, value: value, right: right }
108
- end)
109
-
110
- # It also supports matching against Ruby Arrays
111
- Array.() === []
112
- Array.() === [1]
113
- Array.(*any) === []
114
- Array.(*any) === [1]
115
- Array.(*any) === [1, 2]
116
- Array.(1, *any) === []
117
- Array.(1, *any) === [1]
118
- Array.(1, *any) === [1, 2]
119
-
120
- match [],
121
- on(~Array.to_m) { |v| v }
122
- match [],
123
- on(~Array.()) { |v| v }
124
- match [1, 2],
125
- on(~Array.(*any)) { |v| v }
126
- match [1, 2],
127
- on(~Array.(*any)) { |(v, _)| v }
128
- match [1, 2, 3],
129
- on(Array.(any, *~any)) { |v| v }
130
- match [:first, 1, 2, 3],
131
- on(Array.(:first, ~any, *any)) { |v| v }
132
- match [:+, 1, 2, :foo, :bar],
133
- (on Array.(:+, ~Integer.to_m, ~Integer.to_m, *~any) do |int1, int2, rest|
134
- { sum: int1 + int2, rest: rest }
135
- end)
136
-
137
-
138
- # There is also a more funky syntax for matching
139
- # using #>, #>> and Ruby 1.9 syntax for lambdas `-> {}`.
140
- match Leaf[1],
141
- Leaf.(0) >> :zero,
142
- Leaf.(~any) >-> value do
143
- (1..value).inject(:*) # an expensive computation
144
- end
@@ -1,27 +0,0 @@
1
- # Let's define a Tree
2
- Tree = Algebrick.type do |tree|
3
- variants Empty = atom,
4
- Leaf = type { fields Integer },
5
- Node = type { fields tree, tree }
6
- end
7
-
8
- # Now types `Tree(Empty | Leaf | Node)`, `Empty`, `Leaf(Integer)` and `Node(Tree, Tree)` are defined.
9
- # Let's add a method, don't miss the **pattern matching** example.
10
- module Tree
11
- # compute depth of a tree
12
- def depth
13
- match self,
14
- (on Empty, 0),
15
- (on Leaf, 1),
16
- # ~ will store and pass matched parts to variables left and right
17
- (on Node.(~any, ~any) do |left, right|
18
- 1 + [left.depth, right.depth].max
19
- end)
20
- end
21
- end #
22
-
23
- # Method defined in module `Tree` are passed down to **all** values of type Tree.
24
- Empty.depth
25
- Leaf[10].depth
26
- Node[Leaf[4], Empty].depth
27
- Node[Empty, Node[Leaf[1], Empty]].depth
@@ -1,10 +0,0 @@
1
- Tree = Algebrick.type do |tree|
2
- variants Empty = type,
3
- Leaf = type { fields Integer },
4
- Node = type { fields tree, tree }
5
- end
6
- # Which sets 4 modules representing these types in current module/class
7
- Tree
8
- Empty
9
- Leaf
10
- Node
@@ -1,21 +0,0 @@
1
- # Let's define some types
2
- Maybe = Algebrick.type do
3
- variants None = atom,
4
- Some = type { fields Numeric }
5
- end
6
-
7
- # where the Maybe actually is:
8
- Maybe.class
9
- Maybe.class.superclass
10
- Maybe.class.superclass.superclass
11
- Maybe.class.superclass.superclass.superclass
12
-
13
- # if there is a circular dependency you can define the dependent types inside the block like this:
14
- Tree = Algebrick.type do |tree|
15
- variants Empty = type,
16
- Leaf = type { fields Integer },
17
- Node = type { fields tree, tree }
18
- end
19
- Empty
20
- Leaf
21
- Node
@@ -1,52 +0,0 @@
1
- # Let's define a Tree
2
- Tree = Algebrick.type do |tree|
3
- variants Empty = type,
4
- Leaf = type { fields Integer },
5
- Node = type { fields tree, tree }
6
- end
7
-
8
- # Values of atomic types are represented by itself,
9
- # they are theirs own value.
10
- Empty.kind_of? Algebrick::Value
11
- Empty.kind_of? Algebrick::Type
12
- Empty.kind_of? Empty
13
-
14
- # Values of product types are constructed with #[] and they are immutable.
15
- Leaf[1].kind_of? Algebrick::Value
16
- Leaf[1].kind_of? Leaf
17
- Node[Empty, Empty].kind_of? Node
18
-
19
- # Variant does not have its own values, it uses atoms and products.
20
- Leaf[1].kind_of? Tree
21
- Empty.kind_of? Tree
22
-
23
- # Product can have its fields named.
24
- BinaryTree = BTree = Algebrick.type do |btree|
25
- fields! value: Integer, left: btree, right: btree
26
- variants Tip = atom, btree
27
- end
28
-
29
- # Then values can be created with names
30
- tree1 = BTree[value: 1, left: Tip, right: Tip]
31
- # or without them as before.
32
- BTree[0, Tip, tree1]
33
-
34
- # Fields of products can be read as follows:
35
- # 1. When type has only one field method #value is defined
36
- Leaf[1].value
37
- # 2. By multi-assign
38
- v, left, right = BTree[value: 1, left: Tip, right: Tip]
39
- [v, left, right]
40
- # 3. With #[] method when fields are named
41
- BTree[value: 1, left: Tip, right: Tip][:value]
42
- BTree[value: 1, left: Tip, right: Tip][:left]
43
- # 4. With methods named by fields when fields are named
44
- # (it can be disabled if fields are defined with #fields instead of #fields!)
45
- BTree[1, Tip, Tip].value
46
- BTree[1, Tip, Tip].left
47
-
48
- # Product instantiation raises TypeError when being constructed with wrong type.
49
- Leaf['a'] rescue $!
50
- Node[nil, Empty] rescue $!
51
-
52
-