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/lib/functional/behavior.rb
DELETED
@@ -1,138 +0,0 @@
|
|
1
|
-
module Kernel
|
2
|
-
|
3
|
-
BehaviorError = Class.new(StandardError)
|
4
|
-
|
5
|
-
# Define a behavioral specification (interface).
|
6
|
-
#
|
7
|
-
# @param name [Symbol] the name of the behavior
|
8
|
-
# @param functions [Hash] function names and their arity as key/value pairs
|
9
|
-
def behavior_info(name, functions = {})
|
10
|
-
$__behavior_info__ ||= {}
|
11
|
-
$__behavior_info__[name.to_sym] = functions.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
12
|
-
end
|
13
|
-
|
14
|
-
alias :behaviour_info :behavior_info
|
15
|
-
alias :interface :behavior_info
|
16
|
-
|
17
|
-
module_function :behavior_info
|
18
|
-
module_function :behaviour_info
|
19
|
-
module_function :interface
|
20
|
-
|
21
|
-
# Specify a #behavior_info to enforce on the enclosing class
|
22
|
-
#
|
23
|
-
# @param name [Symbol] name of the #behavior_info being implemented
|
24
|
-
def behavior(name)
|
25
|
-
|
26
|
-
name = name.to_sym
|
27
|
-
raise BehaviorError.new("undefined behavior '#{name}'") if $__behavior_info__[name].nil?
|
28
|
-
|
29
|
-
clazz = self.method(:behavior).receiver
|
30
|
-
|
31
|
-
unless clazz.instance_methods(false).include?(:behaviors)
|
32
|
-
class << clazz
|
33
|
-
def behaviors
|
34
|
-
@behaviors ||= []
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
clazz.behaviors << name
|
40
|
-
|
41
|
-
if self.class == Module
|
42
|
-
(class << self; self; end).class_eval do
|
43
|
-
define_method(:included) do |base|
|
44
|
-
base.class_eval do
|
45
|
-
behavior(name)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
if self.class == Class
|
52
|
-
unless self.respond_to?(:__new)
|
53
|
-
class << clazz
|
54
|
-
alias_method(:__new, :new)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
if $ENABLE_BEHAVIOR_CHECK_ON_CONSTRUCTION == true
|
60
|
-
class << clazz
|
61
|
-
def new(*args, &block)
|
62
|
-
obj = __new(*args, &block)
|
63
|
-
self.ancestors.each do |clazz|
|
64
|
-
if clazz.respond_to?(:behaviors)
|
65
|
-
clazz.behaviors.each do |behavior|
|
66
|
-
valid = obj.behaves_as?(behavior, true)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
return obj
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
alias :behaviour :behavior
|
77
|
-
alias :behaves_as :behavior
|
78
|
-
|
79
|
-
module_function :behavior
|
80
|
-
module_function :behaviour
|
81
|
-
module_function :behaves_as
|
82
|
-
end
|
83
|
-
|
84
|
-
class Object
|
85
|
-
|
86
|
-
# Does the object implement the given #behavior_info?
|
87
|
-
#
|
88
|
-
# @note Will return true if the object implements the required methods. The
|
89
|
-
# object's class hierarchy does not necessarily have to include a corresponding
|
90
|
-
# #behavior call.
|
91
|
-
#
|
92
|
-
# @param name [Symbol] name of the #behavior_info to verify behavior against.
|
93
|
-
# @param abend [Boolean] raise an exception when true and the there are
|
94
|
-
# unimplemented methods
|
95
|
-
#
|
96
|
-
# @return [Boolean] whether or not the required public methods are implemented
|
97
|
-
def behaves_as?(name, abend = false)
|
98
|
-
|
99
|
-
name = name.to_sym
|
100
|
-
bi = $__behavior_info__[name]
|
101
|
-
return false if bi.nil?
|
102
|
-
|
103
|
-
validator = proc do |obj, method, arity|
|
104
|
-
(obj.respond_to?(method) && arity == :any) || obj.method(method).arity == arity
|
105
|
-
end
|
106
|
-
|
107
|
-
if self.is_a?(Class) || self.is_a?(Module)
|
108
|
-
bi = bi.select{|method, arity| method.to_s =~ /^self_/ }
|
109
|
-
end
|
110
|
-
|
111
|
-
bi.each do |method, arity|
|
112
|
-
begin
|
113
|
-
func = method.to_s
|
114
|
-
obj = self
|
115
|
-
|
116
|
-
if (self.is_a?(Class) || self.is_a?(Module)) && func =~ /^self_/
|
117
|
-
func = func.gsub(/^self_/, '')
|
118
|
-
elsif method =~ /^self_/
|
119
|
-
func = func.gsub(/^self_/, '')
|
120
|
-
obj = self.class
|
121
|
-
end
|
122
|
-
|
123
|
-
valid = validator.call(obj, func, arity)
|
124
|
-
raise NameError if abend && ! valid
|
125
|
-
return valid unless valid
|
126
|
-
rescue NameError
|
127
|
-
if abend
|
128
|
-
func = "#{method.to_s.gsub(/^self_/, 'self.')}/#{arity.to_s.gsub(/^any$/, ':any')}"
|
129
|
-
raise BehaviorError.new("undefined callback function ##{func} in #{self} (behavior '#{name}')")
|
130
|
-
else
|
131
|
-
return false
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
return true
|
137
|
-
end
|
138
|
-
end
|
data/lib/functional/behaviour.rb
DELETED
data/lib/functional/catalog.rb
DELETED
@@ -1,487 +0,0 @@
|
|
1
|
-
module Functional
|
2
|
-
|
3
|
-
# A collection of key/value pairs similar to a hash but ordered.
|
4
|
-
# Access is via index (like an array) rather than by key (like a
|
5
|
-
# hash). Supports duplicate keys. Indexing starts at zero.
|
6
|
-
class Catalog
|
7
|
-
include Enumerable
|
8
|
-
|
9
|
-
# Create a new Catalog from the given data. When +data+ is nil
|
10
|
-
# or an empty collection the resulting Catalog will be empty.
|
11
|
-
# When +data+ is an array, hash, or catalog array the appropriate
|
12
|
-
# +#from_+ factory method will be called. The +:from+ option is
|
13
|
-
# used to indicate the type of the source data.
|
14
|
-
#
|
15
|
-
# If a block is given each value in the from the source array will
|
16
|
-
# be passed to the block and the result will be stored as the value
|
17
|
-
# in the Catalog.
|
18
|
-
#
|
19
|
-
# @param [Array, Hash, Catalog] data the data to construct the
|
20
|
-
# Catalog from
|
21
|
-
# @param [Hash] opts processing options
|
22
|
-
#
|
23
|
-
# @option opts [Symbol] :from the type of the data source. Valid values
|
24
|
-
# are :catalog/:catalogue, :hash, :array (default :catalog).
|
25
|
-
def initialize(data=nil, opts={})
|
26
|
-
|
27
|
-
if block_given?
|
28
|
-
|
29
|
-
@data = []
|
30
|
-
data.each do |item|
|
31
|
-
@data << yield(item)
|
32
|
-
end
|
33
|
-
|
34
|
-
else
|
35
|
-
from = opts[:from]
|
36
|
-
from = :array if [:set, :list, :stack, :queue, :vector].include?(from)
|
37
|
-
from = "from_#{from}".to_sym
|
38
|
-
|
39
|
-
if Catalog.respond_to?(from)
|
40
|
-
@data = Catalog.send(from, data)
|
41
|
-
@data = @data.instance_variable_get(:@data)
|
42
|
-
elsif opts[:from].nil? && !data.nil?
|
43
|
-
@data = Catalog.from_catalog(data)
|
44
|
-
@data = @data.instance_variable_get(:@data)
|
45
|
-
else
|
46
|
-
@data = []
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
# Creates a new Catalog object from a hash. Each key/value pair in the
|
52
|
-
# hash will be converted to a key/value array in the new Catalog. If a
|
53
|
-
# block is given each value in the array will be passed to the block
|
54
|
-
# and the result will be stored as the value in the Catalog.
|
55
|
-
def self.from_hash(data = {})
|
56
|
-
collected = []
|
57
|
-
data.each do |key, value|
|
58
|
-
value = yield(value) if block_given?
|
59
|
-
collected << [key, value]
|
60
|
-
end
|
61
|
-
catalog = Catalog.new
|
62
|
-
catalog.instance_variable_set(:@data, collected)
|
63
|
-
return catalog
|
64
|
-
end
|
65
|
-
|
66
|
-
# Creates a new catalog object from an array. Each successive pair of
|
67
|
-
# elements will become a key/value pair in the new Catalog. If the source
|
68
|
-
# array has an odd number of elements the last element will be discarded.
|
69
|
-
# If a block is given each element in the source array will be passed to
|
70
|
-
# the block and the result will be stored in the new Catalog.
|
71
|
-
def self.from_array(*args)
|
72
|
-
collected = []
|
73
|
-
data = args.flatten
|
74
|
-
|
75
|
-
max = ((data.size % 2 == 0) ? data.size-1 : data.size-2)
|
76
|
-
(0..max).step(2) do |index|
|
77
|
-
key = block_given? ? yield(data[index]) : data[index]
|
78
|
-
value = block_given? ? yield(data[index+1]) : data[index+1]
|
79
|
-
collected << [key, value]
|
80
|
-
end
|
81
|
-
|
82
|
-
catalog = Catalog.new
|
83
|
-
catalog.instance_variable_set(:@data, collected)
|
84
|
-
return catalog
|
85
|
-
end
|
86
|
-
|
87
|
-
# Creates a new Catalog object from an array of key/value pairs.
|
88
|
-
# Each key/value pair in the source array will be stored in the new
|
89
|
-
# Catalog. If a block is given each value in the from the source array
|
90
|
-
# will be passed to the block and the result will be stored as the
|
91
|
-
# value in the Catalog.
|
92
|
-
def self.from_catalog(data, *args)
|
93
|
-
collected = []
|
94
|
-
|
95
|
-
if args.empty? && data.size == 2 && !data.first.is_a?(Array)
|
96
|
-
# Catalog.from_catalog([:one, 1])
|
97
|
-
data = [data]
|
98
|
-
elsif !args.empty?
|
99
|
-
#Catalog.from_catalog([:one, 1], [:two, 2], [:three, 3])
|
100
|
-
data = [data] + args
|
101
|
-
end
|
102
|
-
|
103
|
-
data.each do |item|
|
104
|
-
if block_given?
|
105
|
-
collected << [item.first, yield(item.last)]
|
106
|
-
else
|
107
|
-
collected << item
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
catalog = Catalog.new
|
112
|
-
catalog.instance_variable_set(:@data, collected)
|
113
|
-
return catalog
|
114
|
-
end
|
115
|
-
|
116
|
-
class << self
|
117
|
-
alias :from_catalogue :from_catalog
|
118
|
-
end
|
119
|
-
|
120
|
-
# Returns true if self array contains no elements.
|
121
|
-
def empty?
|
122
|
-
size == 0
|
123
|
-
end
|
124
|
-
|
125
|
-
# Returns the number of elements in self. May be zero.
|
126
|
-
def length
|
127
|
-
@data.length
|
128
|
-
end
|
129
|
-
|
130
|
-
alias :size :length
|
131
|
-
|
132
|
-
# Returns the first element, or the first n elements, of the array.
|
133
|
-
# If the array is empty, the first form returns nil, and the second
|
134
|
-
# form returns an empty array.
|
135
|
-
def first
|
136
|
-
@data.first
|
137
|
-
end
|
138
|
-
|
139
|
-
# Returns the last element(s) of self. If the array is empty,
|
140
|
-
# the first form returns nil.
|
141
|
-
def last
|
142
|
-
@data.last
|
143
|
-
end
|
144
|
-
|
145
|
-
# Equality—Two arrays are equal if they contain the same number of
|
146
|
-
# elements and if each element is equal to (according to Object.==)
|
147
|
-
# the corresponding element in the other array.
|
148
|
-
def ==(other)
|
149
|
-
if other.is_a? Catalog
|
150
|
-
return (@data == other.instance_variable_get(:@data))
|
151
|
-
elsif other.is_a? Array
|
152
|
-
return (@data == other)
|
153
|
-
else
|
154
|
-
return false
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
alias :eql? :==
|
159
|
-
|
160
|
-
# Comparison—Returns an integer (-1, 0, or +1) if this array is less
|
161
|
-
# than, equal to, or greater than other_ary. Each object in each
|
162
|
-
# array is compared (using <=>). If any value isn’t equal, then that
|
163
|
-
# inequality is the return value. If all the values found are equal,
|
164
|
-
# then the return is based on a comparison of the array lengths. Thus,
|
165
|
-
# two arrays are “equal” according to Array#<=> if and only if they have
|
166
|
-
# the same length and the value of each element is equal to the value of
|
167
|
-
# the corresponding element in the other array.
|
168
|
-
def <=>(other)
|
169
|
-
other = other.instance_variable_get(:@data) if other.is_a?(Catalog)
|
170
|
-
if other.is_a? Array
|
171
|
-
return @data <=> other
|
172
|
-
else
|
173
|
-
raise TypeError.new("can't convert #{other.class} into Catalog")
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
alias :compare :<=>
|
178
|
-
alias :compare_to :<=>
|
179
|
-
|
180
|
-
# Returns a new array populated with the given objects.
|
181
|
-
def [](index)
|
182
|
-
datum = @data[index]
|
183
|
-
return (datum.nil? ? nil : datum.dup)
|
184
|
-
end
|
185
|
-
|
186
|
-
alias :at :[]
|
187
|
-
|
188
|
-
# Element Assignment—Sets the element at index, or replaces a subarray starting
|
189
|
-
# at start and continuing for length elements, or replaces a subarray specified
|
190
|
-
# by range. If indices are greater than the current capacity of the array, the
|
191
|
-
# array grows automatically. A negative indices will count backward from the end
|
192
|
-
# of the array. Inserts elements if length is zero. An IndexError is raised if a
|
193
|
-
# negative index points past the beginning of the array. See also Array#push,
|
194
|
-
# and Array#unshift.
|
195
|
-
def []=(index, value)
|
196
|
-
if (index >= 0 && index >= @data.size) || (index < 0 && index.abs > @data.size)
|
197
|
-
raise ArgumentError.new('index must reference an existing element')
|
198
|
-
elsif value.is_a?(Hash) && value.size == 1
|
199
|
-
@data[index] = [value.keys.first, value.values.first]
|
200
|
-
elsif value.is_a?(Array) && value.size == 2
|
201
|
-
@data[index] = value.dup
|
202
|
-
else
|
203
|
-
raise ArgumentError.new('value must be a one-element hash or a two-element array')
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
# Returns a string representation of Catalog.
|
208
|
-
def to_s
|
209
|
-
return @data.to_s
|
210
|
-
end
|
211
|
-
|
212
|
-
# Set Intersection—Returns a new array containing elements common to the two
|
213
|
-
# arrays, with no duplicates.
|
214
|
-
def &(other)
|
215
|
-
other = other.instance_variable_get(:@data) if other.is_a?(Catalog)
|
216
|
-
if other.is_a? Array
|
217
|
-
return Catalog.from_catalog(@data & other)
|
218
|
-
else
|
219
|
-
raise TypeError.new("can't convert #{other.class} into Catalog")
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
|
-
alias :intersection :&
|
224
|
-
|
225
|
-
# Concatenation—Returns a new array built by concatenating the two arrays
|
226
|
-
# together to produce a third array.
|
227
|
-
def +(other)
|
228
|
-
other = other.instance_variable_get(:@data) if other.is_a?(Catalog)
|
229
|
-
if other.is_a? Array
|
230
|
-
return Catalog.from_catalog(@data + other)
|
231
|
-
else
|
232
|
-
raise TypeError.new("can't convert #{other.class} into Catalog")
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
|
-
alias :add :+
|
237
|
-
alias :sum :+
|
238
|
-
|
239
|
-
# Set Union—Returns a new array by joining this array with other_array,
|
240
|
-
# removing duplicates.
|
241
|
-
def |(other)
|
242
|
-
other = other.instance_variable_get(:@data) if other.is_a?(Catalog)
|
243
|
-
if other.is_a? Array
|
244
|
-
return Catalog.from_catalog(@data | other)
|
245
|
-
else
|
246
|
-
raise TypeError.new("can't convert #{other.class} into Catalog")
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
|
-
alias :union :|
|
251
|
-
|
252
|
-
# Append—Pushes the given object(s) on to the end of this array.
|
253
|
-
# This expression returns the array itself, so several appends
|
254
|
-
# may be chained together.
|
255
|
-
def push(item)
|
256
|
-
if item.is_a?(Hash) && item.size == 1
|
257
|
-
@data << [item.keys.first, item.values.first]
|
258
|
-
return self
|
259
|
-
elsif item.is_a?(Array) && item.size == 2
|
260
|
-
@data << item
|
261
|
-
return self
|
262
|
-
else
|
263
|
-
raise TypeError.new("can't convert #{item.class} into Catalog")
|
264
|
-
end
|
265
|
-
end
|
266
|
-
|
267
|
-
alias :<< :push
|
268
|
-
alias :append :push
|
269
|
-
|
270
|
-
# Removes the last element from self and returns it, or nil if the
|
271
|
-
# Catalog is empty.
|
272
|
-
def pop
|
273
|
-
if self.empty?
|
274
|
-
return nil
|
275
|
-
else
|
276
|
-
return @data.pop
|
277
|
-
end
|
278
|
-
end
|
279
|
-
|
280
|
-
# Copies the last element from self and returns it, or nil if the
|
281
|
-
# Catalog is empty.
|
282
|
-
def peek
|
283
|
-
if self.empty?
|
284
|
-
return nil
|
285
|
-
else
|
286
|
-
return @data.last.dup
|
287
|
-
end
|
288
|
-
end
|
289
|
-
|
290
|
-
# Returns a new array populated with the keys from this hash.
|
291
|
-
# See also Hash#values.
|
292
|
-
def keys
|
293
|
-
return @data.collect{|item| item.first}
|
294
|
-
end
|
295
|
-
|
296
|
-
# Returns a new array populated with the values from hsh.
|
297
|
-
# See also Hash#keys.
|
298
|
-
def values
|
299
|
-
return @data.collect{|item| item.last}
|
300
|
-
end
|
301
|
-
|
302
|
-
# Calls block once for each key in hsh, passing the key and value
|
303
|
-
# to the block as a two-element array. Because of the assignment
|
304
|
-
# semantics of block parameters, these elements will be split out
|
305
|
-
# if the block has two formal parameters. Also see Hash.each_pair,
|
306
|
-
# which will be marginally more efficient for blocks with two
|
307
|
-
# parameters.
|
308
|
-
def each(&block)
|
309
|
-
@data.each do |item|
|
310
|
-
yield(item)
|
311
|
-
end
|
312
|
-
end
|
313
|
-
|
314
|
-
# Calls block once for each key in hsh, passing the key and value as parameters.
|
315
|
-
def each_pair(&block)
|
316
|
-
@data.each do |item|
|
317
|
-
yield(item.first, item.last)
|
318
|
-
end
|
319
|
-
end
|
320
|
-
|
321
|
-
# Calls block once for each key in hsh, passing the key as a parameter.
|
322
|
-
def each_key(&block)
|
323
|
-
@data.each do |item|
|
324
|
-
yield(item.first)
|
325
|
-
end
|
326
|
-
end
|
327
|
-
|
328
|
-
# Calls block once for each key in hsh, passing the value as a parameter.
|
329
|
-
def each_value(&block)
|
330
|
-
@data.each do |item|
|
331
|
-
yield(item.last)
|
332
|
-
end
|
333
|
-
end
|
334
|
-
|
335
|
-
# Returns true if the given object is present in self (that is,
|
336
|
-
# if any object == anObject), false otherwise.
|
337
|
-
def include?(key=nil, value=nil)
|
338
|
-
if key && value
|
339
|
-
return @data.include?([key, value])
|
340
|
-
elsif key.is_a?(Array)
|
341
|
-
return @data.include?(key)
|
342
|
-
elsif key.is_a?(Hash) && key.size == 1
|
343
|
-
return @data.include?([key.keys.first, key.values.first])
|
344
|
-
else
|
345
|
-
return false
|
346
|
-
end
|
347
|
-
end
|
348
|
-
|
349
|
-
# Element Reference—Returns the element at index, or returns a
|
350
|
-
# subarray starting at start and continuing for length elements,
|
351
|
-
# or returns a subarray specified by range. Negative indices count
|
352
|
-
# backward from the end of the array (-1 is the last element).
|
353
|
-
# Returns nil if the index (or starting index) are out of range.
|
354
|
-
def slice(index, length=nil)
|
355
|
-
if length.nil?
|
356
|
-
catalog = @data.slice(index)
|
357
|
-
else
|
358
|
-
catalog = @data.slice(index, length)
|
359
|
-
end
|
360
|
-
return Catalog.new(catalog)
|
361
|
-
end
|
362
|
-
|
363
|
-
# Deletes the element(s) given by an index (optionally with a length)
|
364
|
-
# or by a range. Returns the deleted object, subarray, or nil if the
|
365
|
-
# index is out of range.
|
366
|
-
def slice!(index, length=nil)
|
367
|
-
if length.nil?
|
368
|
-
catalog = @data.slice!(index)
|
369
|
-
else
|
370
|
-
catalog = @data.slice!(index, length)
|
371
|
-
end
|
372
|
-
return Catalog.new(catalog)
|
373
|
-
end
|
374
|
-
|
375
|
-
# Return a new Catalog created by sorting self according to the natural
|
376
|
-
# sort order of the keys.
|
377
|
-
def sort_by_key
|
378
|
-
sorted = @data.sort{|a, b| a.first <=> b.first}
|
379
|
-
return Catalog.new(sorted)
|
380
|
-
end
|
381
|
-
|
382
|
-
# Sort self according to the natural sort order of the keys. Returns self.
|
383
|
-
def sort_by_key!
|
384
|
-
sorted = @data.sort!{|a, b| a.first <=> b.first}
|
385
|
-
return self
|
386
|
-
end
|
387
|
-
|
388
|
-
# Return a new Catalog created by sorting self according to the natural
|
389
|
-
# sort order of the values.
|
390
|
-
def sort_by_value
|
391
|
-
sorted = @data.sort{|a, b| a.last <=> b.last}
|
392
|
-
return Catalog.new(sorted)
|
393
|
-
end
|
394
|
-
|
395
|
-
# Sort self according to the natural sort order of the values. Returns self.
|
396
|
-
def sort_by_value!
|
397
|
-
sorted = @data.sort!{|a, b| a.last <=> b.last}
|
398
|
-
return self
|
399
|
-
end
|
400
|
-
|
401
|
-
# Returns a new array created by sorting self. Comparisons for
|
402
|
-
# the sort will be done using the <=> operator or using an
|
403
|
-
# optional code block. The block implements a comparison between
|
404
|
-
# a and b, returning -1, 0, or +1. See also Enumerable#sort_by.
|
405
|
-
def sort(&block)
|
406
|
-
sorted = @data.sort(&block)
|
407
|
-
return Catalog.new(sorted)
|
408
|
-
end
|
409
|
-
|
410
|
-
# Sorts self. Comparisons for the sort will be done using the <=>
|
411
|
-
# operator or using an optional code block. The block implements a
|
412
|
-
# comparison between a and b, returning -1, 0, or +1.
|
413
|
-
# See also Enumerable#sort_by.
|
414
|
-
def sort!(&block)
|
415
|
-
sorted = @data.sort!(&block)
|
416
|
-
return self
|
417
|
-
end
|
418
|
-
|
419
|
-
# Returns a new array that is a one-dimensional flattening of self.
|
420
|
-
def to_a
|
421
|
-
return @data.flatten
|
422
|
-
end
|
423
|
-
|
424
|
-
# Returns a new hash by converting each key/value pair in self into
|
425
|
-
# a key/value pair in the hash. When duplicate keys are encountered
|
426
|
-
# the last value associated with that key is kept and the others are
|
427
|
-
# discarded.
|
428
|
-
def to_hash
|
429
|
-
catalog = {}
|
430
|
-
@data.each do |item|
|
431
|
-
catalog[item.first] = item.last
|
432
|
-
end
|
433
|
-
return catalog
|
434
|
-
end
|
435
|
-
|
436
|
-
# Returns a new array that is the dat equivalent of self where each
|
437
|
-
# key/value pair is an two-element array within the returned array.
|
438
|
-
def to_catalog
|
439
|
-
return @data.dup
|
440
|
-
end
|
441
|
-
|
442
|
-
alias :to_catalogue :to_catalog
|
443
|
-
|
444
|
-
# Deletes items from self that are equal to obj. If the item is
|
445
|
-
# not found, returns nil. If the optional code block is given,
|
446
|
-
# returns the result of block if the item is not found.
|
447
|
-
def delete(key, value=nil)
|
448
|
-
item = nil
|
449
|
-
|
450
|
-
if key && value
|
451
|
-
item = @data.delete([key, value])
|
452
|
-
elsif key.is_a? Array
|
453
|
-
item = @data.delete(key)
|
454
|
-
elsif key.is_a? Hash
|
455
|
-
item = @data.delete([key.keys.first, key.values.first])
|
456
|
-
end
|
457
|
-
|
458
|
-
item = yield if item.nil? && block_given?
|
459
|
-
return item
|
460
|
-
end
|
461
|
-
|
462
|
-
# Deletes the element at the specified index, returning that element,
|
463
|
-
# or nil if the index is out of range. See also Array#slice!.
|
464
|
-
def delete_at(index)
|
465
|
-
item = @data.delete_at(index)
|
466
|
-
item = yield if item.nil? && block_given?
|
467
|
-
return item
|
468
|
-
end
|
469
|
-
|
470
|
-
# Deletes every element of self for which block evaluates to true.
|
471
|
-
def delete_if(&block)
|
472
|
-
raise ArgumentError.new('no block supplied') unless block_given?
|
473
|
-
if block.arity <= 1
|
474
|
-
items = @data.delete_if(&block)
|
475
|
-
else
|
476
|
-
items = []
|
477
|
-
@data.each do |key, value|
|
478
|
-
items << [key, value] if yield(key, value)
|
479
|
-
end
|
480
|
-
items.each {|item| @data.delete(item)}
|
481
|
-
end
|
482
|
-
return self
|
483
|
-
end
|
484
|
-
end
|
485
|
-
|
486
|
-
class Catalogue < Catalog; end
|
487
|
-
end
|