functional-ruby 0.7.7 → 1.0.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 +4 -4
- data/README.md +92 -152
- data/doc/memo.txt +192 -0
- data/doc/pattern_matching.txt +485 -0
- data/doc/protocol.txt +221 -0
- data/doc/record.txt +144 -0
- data/doc/thread_safety.txt +8 -0
- data/lib/functional.rb +48 -18
- data/lib/functional/abstract_struct.rb +161 -0
- data/lib/functional/delay.rb +117 -0
- data/lib/functional/either.rb +222 -0
- data/lib/functional/memo.rb +93 -0
- data/lib/functional/method_signature.rb +72 -0
- data/lib/functional/option.rb +209 -0
- data/lib/functional/pattern_matching.rb +117 -100
- data/lib/functional/protocol.rb +157 -0
- data/lib/functional/protocol_info.rb +193 -0
- data/lib/functional/record.rb +155 -0
- data/lib/functional/type_check.rb +112 -0
- data/lib/functional/union.rb +152 -0
- data/lib/functional/version.rb +3 -1
- data/spec/functional/abstract_struct_shared.rb +154 -0
- data/spec/functional/complex_pattern_matching_spec.rb +205 -0
- data/spec/functional/configuration_spec.rb +17 -0
- data/spec/functional/delay_spec.rb +147 -0
- data/spec/functional/either_spec.rb +237 -0
- data/spec/functional/memo_spec.rb +207 -0
- data/spec/functional/option_spec.rb +292 -0
- data/spec/functional/pattern_matching_spec.rb +279 -276
- data/spec/functional/protocol_info_spec.rb +444 -0
- data/spec/functional/protocol_spec.rb +274 -0
- data/spec/functional/record_spec.rb +175 -0
- data/spec/functional/type_check_spec.rb +103 -0
- data/spec/functional/union_spec.rb +110 -0
- data/spec/spec_helper.rb +6 -4
- metadata +55 -45
- data/lib/functional/behavior.rb +0 -138
- data/lib/functional/behaviour.rb +0 -2
- data/lib/functional/catalog.rb +0 -487
- data/lib/functional/collection.rb +0 -403
- data/lib/functional/inflect.rb +0 -127
- data/lib/functional/platform.rb +0 -120
- data/lib/functional/search.rb +0 -132
- data/lib/functional/sort.rb +0 -41
- data/lib/functional/utilities.rb +0 -189
- data/md/behavior.md +0 -188
- data/md/catalog.md +0 -32
- data/md/collection.md +0 -32
- data/md/inflect.md +0 -32
- data/md/pattern_matching.md +0 -512
- data/md/platform.md +0 -32
- data/md/search.md +0 -32
- data/md/sort.md +0 -32
- data/md/utilities.md +0 -55
- data/spec/functional/behavior_spec.rb +0 -528
- data/spec/functional/catalog_spec.rb +0 -1206
- data/spec/functional/collection_spec.rb +0 -752
- data/spec/functional/inflect_spec.rb +0 -85
- data/spec/functional/integration_spec.rb +0 -205
- data/spec/functional/platform_spec.rb +0 -501
- data/spec/functional/search_spec.rb +0 -187
- data/spec/functional/sort_spec.rb +0 -61
- data/spec/functional/utilities_spec.rb +0 -277
data/doc/protocol.txt
ADDED
@@ -0,0 +1,221 @@
|
|
1
|
+
# @!macro [new] protocol
|
2
|
+
#
|
3
|
+
# ## Rationale
|
4
|
+
#
|
5
|
+
# Traditional object orientation implements polymorphism inheritance. The *Is-A*
|
6
|
+
# relationship indicates that one object "is a" instance of another object.
|
7
|
+
# Implicit in this relationship, however, is the concept of [type](http://en.wikipedia.org/wiki/Data_type).
|
8
|
+
# Every Ruby object has a *type*, and that type is the name of its `Class` or
|
9
|
+
# `Module`. The Ruby runtime provides a number of reflective methods that allow
|
10
|
+
# objects to be interrogated for type information. The principal of thses is the
|
11
|
+
# `is_a?` (alias `kind_of`) method defined in class `Object`.
|
12
|
+
#
|
13
|
+
# Unlike many traditional object oriented languages, Ruby is a [dynamically typed](http://en.wikipedia.org/wiki/Dynamic_typing#DYNAMIC)
|
14
|
+
# language. Types exist but the runtime is free to cast one type into another
|
15
|
+
# at any time. Moreover, Ruby is a [duck typed](http://en.wikipedia.org/wiki/Duck_typing).
|
16
|
+
# If an object "walks like a duck and quacks like a duck then it must be a duck."
|
17
|
+
# When a method needs called on an object Ruby does not check the type of the object,
|
18
|
+
# it simply checks to see if the requested function exists with the proper
|
19
|
+
# [arity](http://en.wikipedia.org/wiki/Arity) and, if it does, dispatches the call.
|
20
|
+
# The duck type analogue to `is_a?` is `respond_to?`. Thus an object can be interrogated
|
21
|
+
# for its behavior rather than its type.
|
22
|
+
#
|
23
|
+
# Although Ruby offers several methods for reflecting on the behavior of a module/class/object,
|
24
|
+
# such as `method`, `instance_methods`, `const_defined?`, the aforementioned `respond_to?`,
|
25
|
+
# and others, Ruby lacks a convenient way to group collections of methods in any way that
|
26
|
+
# does not involve type. Both modules and classes provide mechanisms for combining
|
27
|
+
# methods into cohesive abstractions, but they both imply type. This is anathema to Ruby's
|
28
|
+
# dynamism and duck typing. What Ruby needs is a way to collect a group of method names
|
29
|
+
# and signatures into a cohesive collection that embraces duck typing and dynamic dispatch.
|
30
|
+
# This is what protocols do.
|
31
|
+
#
|
32
|
+
# ## Specifying
|
33
|
+
#
|
34
|
+
# A "protocol" is a loose collection of method, attribute, and constant names with optional
|
35
|
+
# arity values. The protocol definition does very little on its own. The power of protocols
|
36
|
+
# is that they provide a way for modules, classes, and objects to be interrogated with
|
37
|
+
# respect to common behavior, not common type. At the core a protocol is nothing more
|
38
|
+
# than a collection of `respond_to?` method calls that ask the question "Does this thing
|
39
|
+
# *behave* like this other thing."
|
40
|
+
#
|
41
|
+
# Protocols are specified with the `Functional::SpecifyProtocol` method. It takes one parameter,
|
42
|
+
# the name of the protocol, and a block which contains the protocol specification. This registers
|
43
|
+
# the protocol specification and makes it available for use later when interrogating ojects
|
44
|
+
# for their behavior.
|
45
|
+
#
|
46
|
+
# ### Defining Attributes, Methods, and Constants
|
47
|
+
#
|
48
|
+
# A single protocol specification can include definition for attributes, methods,
|
49
|
+
# and constants. Methods and attributes can be defined as class/module methods or
|
50
|
+
# as instance methods. Within the a protocol specification each item must include
|
51
|
+
# the symbolic name of the item being defined.
|
52
|
+
#
|
53
|
+
# ```ruby
|
54
|
+
# Functional::SpecifyProtocol(:KitchenSink) do
|
55
|
+
# instance_method :instance_method
|
56
|
+
# class_method :class_method
|
57
|
+
# attr_accessor :attr_accessor
|
58
|
+
# attr_reader :attr_reader
|
59
|
+
# attr_writer :attr_writer
|
60
|
+
# class_attr_accessor :class_attr_accessor
|
61
|
+
# class_attr_reader :class_attr_reader
|
62
|
+
# class_attr_writer :class_attr_writer
|
63
|
+
# constant :CONSTANT
|
64
|
+
# end
|
65
|
+
# ```
|
66
|
+
#
|
67
|
+
# Definitions for accessors are expanded at specification into the apprporiate
|
68
|
+
# method(s). Which means that this:
|
69
|
+
#
|
70
|
+
# ```ruby
|
71
|
+
# Functional::SpecifyProtocol(:Name) do
|
72
|
+
# attr_accessor :first
|
73
|
+
# attr_accessor :middle
|
74
|
+
# attr_accessor :last
|
75
|
+
# attr_accessor :suffix
|
76
|
+
# end
|
77
|
+
# ```
|
78
|
+
#
|
79
|
+
# is the same as:
|
80
|
+
#
|
81
|
+
# ```ruby
|
82
|
+
# Functional::SpecifyProtocol(:Name) do
|
83
|
+
# instance_method :first
|
84
|
+
# instance_method :first=
|
85
|
+
# instance_method :middle
|
86
|
+
# instance_method :middle=
|
87
|
+
# instance_method :last
|
88
|
+
# instance_method :last=
|
89
|
+
# instance_method :suffix
|
90
|
+
# instance_method :suffix=
|
91
|
+
# end
|
92
|
+
# ```
|
93
|
+
#
|
94
|
+
# Protocols only care about the methods themselves, not how they were declared.
|
95
|
+
#
|
96
|
+
# ### Arity
|
97
|
+
#
|
98
|
+
# In addition to defining *which* methods exist, the required method arity can
|
99
|
+
# indicated. Arity is optional. When no arity is given any arity will be expected.
|
100
|
+
# The arity rules follow those defined for the `#arity` method of Ruby's
|
101
|
+
# [Method class](http://www.ruby-doc.org/core-2.1.2/Method.html#method-i-arity):
|
102
|
+
#
|
103
|
+
# * Methods with a fixed number of arguments have a non-negative arity
|
104
|
+
# * Methods with optional arguments have an arity `-n - 1`, where n is the number of required arguments
|
105
|
+
# * Methods with a variable number of arguments have an arity of `-1`
|
106
|
+
#
|
107
|
+
# ```ruby
|
108
|
+
# Functional::SpecifyProtocol(:Foo) do
|
109
|
+
# instance_method :any_args
|
110
|
+
# instance_method :no_args, 0
|
111
|
+
# instance_method :three_args, 3
|
112
|
+
# instance_method :optional_args, -2
|
113
|
+
# instance_method :variable_args, -1
|
114
|
+
# end
|
115
|
+
#
|
116
|
+
# class Bar
|
117
|
+
#
|
118
|
+
# def any_args(a, b, c=1, d=2, *args)
|
119
|
+
# end
|
120
|
+
#
|
121
|
+
# def no_args
|
122
|
+
# end
|
123
|
+
#
|
124
|
+
# def three_args(a, b, c)
|
125
|
+
# end
|
126
|
+
#
|
127
|
+
# def optional_args(a, b=1, c=2)
|
128
|
+
# end
|
129
|
+
#
|
130
|
+
# def variable_args(*args)
|
131
|
+
# end
|
132
|
+
# end
|
133
|
+
# ```
|
134
|
+
#
|
135
|
+
# ## Reflection
|
136
|
+
#
|
137
|
+
# Once a protocol has been defined, any class, method, or object may be interrogated
|
138
|
+
# for adherence to one or more protocol specifications. The methods of the
|
139
|
+
# `Functional::Protocol` classes provide this capability. The `Satisfy?` method
|
140
|
+
# takes a module/class/object as the first parameter and one or more protocol names
|
141
|
+
# as the second and subsequent parameters. It returns a boolean value indicating
|
142
|
+
# whether the given object satisfies the protocol requirements:
|
143
|
+
#
|
144
|
+
# ```ruby
|
145
|
+
# Functional::SpecifyProtocol(:Queue) do
|
146
|
+
# instance_method :push, 1
|
147
|
+
# instance_method :pop, 0
|
148
|
+
# instance_method :length, 0
|
149
|
+
# end
|
150
|
+
#
|
151
|
+
# Functional::SpecifyProtocol(:List) do
|
152
|
+
# instance_method :[]=, 2
|
153
|
+
# instance_method :[], 1
|
154
|
+
# instance_method :each, 0
|
155
|
+
# instance_method :length, 0
|
156
|
+
# end
|
157
|
+
#
|
158
|
+
# Functional::Protocol::Satisfy?(Queue, :Queue) #=> true
|
159
|
+
# Functional::Protocol::Satisfy?(Queue, :List) #=> false
|
160
|
+
#
|
161
|
+
# list = [1, 2, 3]
|
162
|
+
# Functional::Protocol::Satisfy?(Array, :List, :Queue) #=> true
|
163
|
+
# Functional::Protocol::Satisfy?(list, :List, :Queue) #=> true
|
164
|
+
#
|
165
|
+
# Functional::Protocol::Satisfy?(Hash, :Queue) #=> false
|
166
|
+
#
|
167
|
+
# Functional::Protocol::Satisfy?('foo bar baz', :List) #=> false
|
168
|
+
# ```
|
169
|
+
#
|
170
|
+
# The `Satisfy!` method performs the exact same check but instead raises an exception
|
171
|
+
# when the protocol is not satisfied:
|
172
|
+
#
|
173
|
+
# ```
|
174
|
+
# 2.1.2 :021 > Functional::Protocol::Satisfy!(Queue, :List)
|
175
|
+
# Functional::ProtocolError: Value (Class) 'Thread::Queue' does not behave as all of: :List.
|
176
|
+
# from /Projects/functional-ruby/lib/functional/protocol.rb:67:in `error'
|
177
|
+
# from /Projects/functional-ruby/lib/functional/protocol.rb:36:in `Satisfy!'
|
178
|
+
# from (irb):21
|
179
|
+
# ...
|
180
|
+
# ```
|
181
|
+
# The `Functional::Protocol` module can be included within other classes
|
182
|
+
# to eliminate the namespace requirement when calling:
|
183
|
+
#
|
184
|
+
# ```ruby
|
185
|
+
# class MessageFormatter
|
186
|
+
# include Functional::Protocol
|
187
|
+
#
|
188
|
+
# def format(message)
|
189
|
+
# if Satisfy?(message, :Internal)
|
190
|
+
# format_internal_message(message)
|
191
|
+
# elsif Satisfy?(message, :Error)
|
192
|
+
# format_error_message(message)
|
193
|
+
# else
|
194
|
+
# format_generic_message(message)
|
195
|
+
# end
|
196
|
+
# end
|
197
|
+
#
|
198
|
+
# private
|
199
|
+
#
|
200
|
+
# def format_internal_message(message)
|
201
|
+
# # format the message...
|
202
|
+
# end
|
203
|
+
#
|
204
|
+
# def format_error_message(message)
|
205
|
+
# # format the message...
|
206
|
+
# end
|
207
|
+
#
|
208
|
+
# def format_generic_message(message)
|
209
|
+
# # format the message...
|
210
|
+
# end
|
211
|
+
# ```
|
212
|
+
#
|
213
|
+
# ## Inspiration
|
214
|
+
#
|
215
|
+
# Protocols and similar functionality exist in several other programming languages.
|
216
|
+
# A few languages that provided inspiration for this inplementation are:
|
217
|
+
#
|
218
|
+
# * Clojure [protocol](http://clojure.org/protocols)
|
219
|
+
# * Erlang [behaviours](http://www.erlang.org/doc/design_principles/des_princ.html#id60128)
|
220
|
+
# * Objective-C [protocol](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithProtocols/WorkingwithProtocols.html)
|
221
|
+
# (and the corresponding Swift [protocol](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html))
|
data/doc/record.txt
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
# @!macro [new] record
|
2
|
+
#
|
3
|
+
# ## Declaration
|
4
|
+
#
|
5
|
+
# A `Record` class is declared in a manner identical to that used with Ruby's `Struct`.
|
6
|
+
# The class method `new` is called with a list of one or more field names (symbols).
|
7
|
+
# A new class will then be dynamically generated along with the necessary reader
|
8
|
+
# attributes, one for each field. The newly created class will be anonymous and
|
9
|
+
# will mixin `Functional::AbstractStruct`. The best practice is to assign the newly
|
10
|
+
# created record class to a constant:
|
11
|
+
#
|
12
|
+
# ```ruby
|
13
|
+
# Customer = Functional::Record.new(:name, :address) #=> Customer
|
14
|
+
# ```
|
15
|
+
#
|
16
|
+
# Alternatively, the name of the record class, as a string, can be given as the
|
17
|
+
# first parameter. In this case the new record class will be created as a constant
|
18
|
+
# within the `Record` module:
|
19
|
+
#
|
20
|
+
# ```ruby
|
21
|
+
# Functional::Record.new("Customer", :name, :address) #=> Functional::Record::Customer
|
22
|
+
# ```
|
23
|
+
#
|
24
|
+
# **NOTE:** The `new` method of `Record` does not accept a block the way Ruby's `Struct`
|
25
|
+
# does. The block passed to the `new` method of `Record` is used to set mandatory fields
|
26
|
+
# and default values (see below). It is *not* used for additional class declarations.
|
27
|
+
#
|
28
|
+
# ### Construction
|
29
|
+
#
|
30
|
+
# Construction of a new object from a record is slightly different than for a Ruby `Struct`.
|
31
|
+
# The constructor for a struct class may take zero or more field values and will use those
|
32
|
+
# values to popuate the fields. The values passed to the constructor are assumed to be in
|
33
|
+
# the same order as the fields were defined. This works for a struct because it is
|
34
|
+
# mutable--the field values may be changed after instanciation. Therefore it is not
|
35
|
+
# necessary to provide all values to a stuct at creation. This is not the case for a
|
36
|
+
# record. A record is immutable. The values for all its fields must be set at instanciation
|
37
|
+
# because they cannot be changed later. When creating a new record object the constructor
|
38
|
+
# will accept a collection of field/value pairs in hash syntax and will create the new
|
39
|
+
# record with the given values:
|
40
|
+
#
|
41
|
+
# ```ruby
|
42
|
+
# Customer.new(name: 'Dave', address: '123 Main')
|
43
|
+
# #=> #<record Customer :name=>"Dave", :address=>"123 Main">
|
44
|
+
#
|
45
|
+
# Functional::Record::Customer.new(name: 'Dave', address: '123 Main')
|
46
|
+
# #=> #<record Functional::Record::Customer :name=>"Dave", :address=>"123 Main">
|
47
|
+
# ```
|
48
|
+
#
|
49
|
+
# ### Default Values
|
50
|
+
#
|
51
|
+
# By default, all record fields are set to `nil` at instanciation unless explicity set
|
52
|
+
# via the constructor. It is possible to specify default values other than `nil` for
|
53
|
+
# zero or more of the fields when a new record class is created. The `new` method of
|
54
|
+
# `Record` accepts a block which can be used to declare new default values:
|
55
|
+
#
|
56
|
+
# ```ruby
|
57
|
+
# Address = Functional::Record.new(:street_line_1, :street_line_2,
|
58
|
+
# :city, :state, :postal_code, :country) do
|
59
|
+
# default :state, 'Ohio'
|
60
|
+
# default :country, 'USA'
|
61
|
+
# end
|
62
|
+
# #=> Address
|
63
|
+
# ```
|
64
|
+
#
|
65
|
+
# When a new object is created from a record class with explicit default values, those
|
66
|
+
# values will be used for the appropriate fields when no other value is given at
|
67
|
+
# construction:
|
68
|
+
#
|
69
|
+
# ```ruby
|
70
|
+
# Address.new(street_line_1: '2401 Ontario St',
|
71
|
+
# city: 'Cleveland', postal_code: 44115)
|
72
|
+
# #=> #<record Address :street_line_1=>"2401 Ontario St", :street_line_2=>nil, :city=>"Cleveland", :state=>"Ohio", :postal_code=>44115, :country=>"USA">
|
73
|
+
# ```
|
74
|
+
#
|
75
|
+
# Of course, if a value for a field is given at construction that value will be used instead
|
76
|
+
# of the custom default:
|
77
|
+
#
|
78
|
+
# ```ruby
|
79
|
+
# Address.new(street_line_1: '1060 W Addison St',
|
80
|
+
# city: 'Chicago', state: 'Illinois', postal_code: 60613)
|
81
|
+
# #=> #<record Address :street_line_1=>"1060 W Addison St", :street_line_2=>nil, :city=>"Chicago", :state=>"Illinois", :postal_code=>60613, :country=>"USA">
|
82
|
+
# ```
|
83
|
+
#
|
84
|
+
# ### Mandatory Fields
|
85
|
+
#
|
86
|
+
# By default, all record fields are optional. It is perfectly legal for a record
|
87
|
+
# object to exist with all its fields set to `nil`. During declaration of a new record
|
88
|
+
# class the block passed to `Record.new` can also be used to indicate which fields
|
89
|
+
# are mandatory. When a new object is created from a record with mandatory fields
|
90
|
+
# an exception will be thrown if any of those fields are nil:
|
91
|
+
#
|
92
|
+
# ```ruby
|
93
|
+
# Name = Functional::Record.new(:first, :middle, :last, :suffix) do
|
94
|
+
# mandatory :first, :last
|
95
|
+
# end
|
96
|
+
# #=> Name
|
97
|
+
#
|
98
|
+
# Name.new(first: 'Joe', last: 'Armstrong')
|
99
|
+
# #=> #<record Name :first=>"Joe", :middle=>nil, :last=>"Armstrong", :suffix=>nil>
|
100
|
+
#
|
101
|
+
# Name.new(first: 'Matz') #=> ArgumentError: mandatory fields must not be nil
|
102
|
+
# ```
|
103
|
+
#
|
104
|
+
# Of course, declarations for default values and mandatory fields may be used
|
105
|
+
# together:
|
106
|
+
#
|
107
|
+
# ```ruby
|
108
|
+
# Person = Functional::Record.new(:first_name, :middle_name, :last_name,
|
109
|
+
# :street_line_1, :street_line_2,
|
110
|
+
# :city, :state, :postal_code, :country) do
|
111
|
+
# mandatory :first_name, :last_name
|
112
|
+
# mandatory :country
|
113
|
+
# default :state, 'Ohio'
|
114
|
+
# default :country, 'USA'
|
115
|
+
# end
|
116
|
+
# #=> Person
|
117
|
+
# ```
|
118
|
+
#
|
119
|
+
# ### Default Value Memoization
|
120
|
+
#
|
121
|
+
# Note that the block provided to `Record.new` is processed once and only once
|
122
|
+
# when the new record class is declared. Thereafter the results are memoized
|
123
|
+
# and copied (via `clone`, unless uncloneable) each time a new record object
|
124
|
+
# is created. Default values should be simple types like `String`, `Fixnum`,
|
125
|
+
# and `Boolean`. If complex operations need performed when setting default
|
126
|
+
# values the a `Class` should be used instead of a `Record`.
|
127
|
+
#
|
128
|
+
# ## Inspiration
|
129
|
+
#
|
130
|
+
# Neither struct nor records are new to computing. Both have been around for a very
|
131
|
+
# long time. Mutable structs can be found in many languages including
|
132
|
+
# [Ruby](http://www.ruby-doc.org/core-2.1.2/Struct.html),
|
133
|
+
# [Go](http://golang.org/ref/spec#Struct_types),
|
134
|
+
# [C](http://en.wikipedia.org/wiki/Struct_(C_programming_language)),
|
135
|
+
# and [C#](http://msdn.microsoft.com/en-us/library/ah19swz4.aspx),
|
136
|
+
# just to name a few. Immutable records exist primarily in functional languages
|
137
|
+
# like [Haskell](http://en.wikibooks.org/wiki/Haskell/More_on_datatypes#Named_Fields_.28Record_Syntax.29),
|
138
|
+
# Clojure, and Erlang. The latter two are the main influences for this implementation.
|
139
|
+
#
|
140
|
+
# * [Ruby Struct](http://www.ruby-doc.org/core-2.1.2/Struct.html)
|
141
|
+
# * [Clojure Datatypes](http://clojure.org/datatypes)
|
142
|
+
# * [Clojure *defrecord* macro](http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/defrecord)
|
143
|
+
# * [Erlang Records (Reference)](http://www.erlang.org/doc/reference_manual/records.html)
|
144
|
+
# * [Erlang Records (Examples)](http://www.erlang.org/doc/programming_examples/records.html)
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# @!macro [new] thread_safe_immutable_object
|
2
|
+
#
|
3
|
+
# @note This is an immutable, read-only, frozen, thread safe object that can
|
4
|
+
# be used in concurrent systems. Thread safety guarantees *cannot* be made
|
5
|
+
# about objects contained *within* this object, however. Ruby variables are
|
6
|
+
# mutable references to mutable objects. This cannot be changed. The best
|
7
|
+
# practice it to only encapsulate immutable, frozen, or thread safe objects.
|
8
|
+
# Ultimately, thread safety is the responsibility of the programmer.
|
data/lib/functional.rb
CHANGED
@@ -1,26 +1,56 @@
|
|
1
|
-
require 'functional/
|
2
|
-
require 'functional/
|
3
|
-
require 'functional/
|
4
|
-
require 'functional/
|
5
|
-
require 'functional/inflect'
|
1
|
+
require 'functional/delay'
|
2
|
+
require 'functional/either'
|
3
|
+
require 'functional/memo'
|
4
|
+
require 'functional/option'
|
6
5
|
require 'functional/pattern_matching'
|
7
|
-
require 'functional/
|
8
|
-
require 'functional/
|
9
|
-
require 'functional/
|
10
|
-
require 'functional/
|
6
|
+
require 'functional/protocol'
|
7
|
+
require 'functional/protocol_info'
|
8
|
+
require 'functional/record'
|
9
|
+
require 'functional/type_check'
|
10
|
+
require 'functional/union'
|
11
11
|
require 'functional/version'
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
Functional::SpecifyProtocol(:Disposition) do
|
14
|
+
instance_method :value, 0
|
15
|
+
instance_method :value?, 0
|
16
|
+
instance_method :reason, 0
|
17
|
+
instance_method :reason?, 0
|
18
|
+
instance_method :fulfilled?, 0
|
19
|
+
instance_method :rejected?, 0
|
20
|
+
end
|
17
21
|
|
22
|
+
# Erlang, Clojure, and Go inspired functional programming tools to Ruby.
|
18
23
|
module Functional
|
19
24
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
+
# Infinity
|
26
|
+
Infinity = 1/0.0
|
27
|
+
|
28
|
+
# Not a number
|
29
|
+
NaN = 0/0.0
|
30
|
+
|
31
|
+
# A gem-level configuration class.
|
32
|
+
# @!visibility private
|
33
|
+
class Configuration
|
34
|
+
end
|
35
|
+
|
36
|
+
# create the default configuration on load
|
37
|
+
# @!visibility private
|
38
|
+
@configuration = Configuration.new
|
39
|
+
|
40
|
+
# The current gem configutation.
|
41
|
+
#
|
42
|
+
# @return [Functional::Configuration]
|
43
|
+
#
|
44
|
+
# @!visibility private
|
45
|
+
def self.configuration
|
46
|
+
@configuration
|
47
|
+
end
|
48
|
+
|
49
|
+
# Perform gem-level configuration.
|
50
|
+
#
|
51
|
+
# @yield the configuration commands
|
52
|
+
# @yieldparam [Functional::Configuration] the current configuration object
|
53
|
+
def self.configure
|
54
|
+
yield(configuration)
|
25
55
|
end
|
26
56
|
end
|