random-accessible 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,302 @@
1
+ # Author:: Natsuki Kawai (natsuki.kawai@gmail.com)
2
+ # Copyright:: Copyright 2011 Natsuki Kawai
3
+ # License:: 2-clause BSDL or Ruby's
4
+
5
+
6
+ require 'common-traits'
7
+
8
+ # RandomWritable mixin provides write-access methods of Array.
9
+ # The class must provide one or more methods from replace-accessor
10
+ # ([]=, replace_at, replace_access) and shrink-accessor (shrink) respectively.
11
+ # The class may provide insert-accessor (insert_access, insert_at, insert)
12
+ # and delete-accessor (delete_access, delete_at).
13
+ # replace_at(pos, val) has same function as []= but it does not need to accept
14
+ # Range or start/length arguments.
15
+ # The class may provide one size-provider (size, length).
16
+ # The class may provide (size, length).
17
+ # replace_access(pos) is similar to replace_at. But the mixin guarantees
18
+ # that 0 <= pos, and pos < size if the class has a size-provider.
19
+ # insert_at(pos, val) is fixed-number-argument version of insert(pos, *val)
20
+ # insert_access(pos, val) is similar to insert_at. But the mixin guarantees
21
+ # that 0 <= pos, and pos < size if the class has a size-provider.
22
+ # delete_access is similar to delete_at. But the mixin guarantees
23
+ # that 0 <= pos, and pos < size if the class has a size-provider.
24
+ # If the class does not provide size-provider, insert_accessor, or delete_accessor,
25
+ # some of the methods of the module raises NotImplementedError.
26
+ # Please see the document of each method.
27
+ module RandomWritable
28
+
29
+ include RandomAccessible::CommonTraits
30
+
31
+ # Raises NotImplemented Error.
32
+ # Override this on user classes.
33
+ def insert_access(pos, val)
34
+ raise NotImplementedError
35
+ end
36
+
37
+ # Raises NotImplemented Error.
38
+ # Override this on user classes.
39
+ def delete_access(pos)
40
+ raise NotImplementedError
41
+ end
42
+
43
+ # replace_at is similar to Array#[]=.
44
+ # But it does not need to accept Range or start/length arguments.
45
+ def replace_at(pos, val)
46
+ if pos < 0
47
+ pos = size + pos
48
+ end
49
+ if has_size? && size <= pos
50
+ expand(pos - size + 1)
51
+ end
52
+ replace_access(pos, val)
53
+ return self
54
+ end
55
+
56
+ # Empty method.
57
+ # Override if you need something to do
58
+ # when expanding the object.
59
+ def expand(n)
60
+ # Nothing to do.
61
+ end
62
+
63
+ # Fixed-number-argument version of insert(pos, *val)
64
+ # This method raises NotImplementedError
65
+ # if the class does not provide insert_access(pos, val).
66
+ def insert_at(pos, val)
67
+ if pos < 0
68
+ pos = size + pos + 1
69
+ end
70
+ if pos < 0
71
+ raise IndexError, "index is too small"
72
+ end
73
+ insert_access(pos, val)
74
+ return self
75
+ end
76
+
77
+ # Same as Array's.
78
+ # This method raises NotImplementedError
79
+ # if the class provides no size-provider and pos is negative
80
+ # This method raises NotImplementedError
81
+ # if the class does not provide delete_access.
82
+ def delete_at(pos)
83
+ if pos < 0
84
+ pos = size + pos
85
+ end
86
+ if pos < 0 || (has_size? && size <= pos)
87
+ return nil
88
+ end
89
+ return delete_access(pos)
90
+ end
91
+
92
+ # Same as Array's.
93
+ # This method raises NotImplementedError
94
+ # if the class provides no size-provider.
95
+ def <<(obj)
96
+ index = size
97
+ expand(1)
98
+ replace_access(index, obj)
99
+ return self
100
+ end
101
+
102
+ # Same as Array's.
103
+ # This method raises NotImplementedError
104
+ # if the class provides no size-provider and the argument is (or includes) negative.
105
+ def []=(*args)
106
+ if args.size <= 1 || 4 <= args.size
107
+ raise ArgumentError, "wrong number of arguments (#{args.size} for 2..3)"
108
+ end
109
+
110
+ val = args.pop
111
+ if args.size == 2
112
+ start = args[0].to_int
113
+ len = args[1].to_int
114
+ if has_size?
115
+ if start < -size
116
+ raise IndexError, "index #{start} too small for array; minimun: #{-size}"
117
+ end
118
+ else
119
+ if start < 0
120
+ raise IndexError, "index #{start} too small for array; minimun: 0"
121
+ end
122
+ end
123
+ if val.respond_to? :to_ary
124
+ val = val.to_ary
125
+ else
126
+ val = [val]
127
+ end
128
+ if has_size?
129
+ if start + len > size
130
+ len = size - start + 1
131
+ end
132
+ if len <= 0
133
+ len = 1
134
+ end
135
+ end
136
+ if val.size < len
137
+ (len - val.size).times do
138
+ delete_at(start + val.size)
139
+ end
140
+ val.size.times do |i|
141
+ replace_at(start + i, val[i])
142
+ end
143
+ elsif val.size >= len
144
+ len.times do |i|
145
+ replace_at(start + i, val[i])
146
+ end
147
+ (val.size - len).times do |i|
148
+ insert_at(start + len + i, val[len + i])
149
+ end
150
+ end
151
+ elsif args[0].is_a? Range
152
+ range = args[0]
153
+ if !has_size?
154
+ if range.first < 0
155
+ raise RangeError, "#{range.to_s} out of range"
156
+ end
157
+ elsif range.first < -size
158
+ raise RangeError, "#{range.to_s} out of range"
159
+ end
160
+ first = range.first
161
+ last = range.last
162
+ last += 1 unless range.exclude_end?
163
+ self[first, last - first] = val
164
+ else
165
+ replace_at(args[0].to_int, val)
166
+ end
167
+ end
168
+
169
+ # Same as Array's.
170
+ # This method raises NotImplementedError
171
+ # if the class provides no size-provider.
172
+ def clear
173
+ shrink(size)
174
+ end
175
+
176
+ # Same as Array's.
177
+ # This method raises NotImplementedError
178
+ # if the class provides no size-provider.
179
+ # Note that the argument must accept read access.
180
+ def concat(other)
181
+ i = size
182
+ expand(other.size)
183
+ other.each do |el|
184
+ replace_at(i, el)
185
+ i += 1
186
+ end
187
+ end
188
+
189
+ # Same as Array's.
190
+ # This method raises NotImplementedError
191
+ # if the class provides no size-provider and the arguments does not include
192
+ # Range nor start/length.
193
+ def fill(*args, &block)
194
+ if args.size > (block.nil? ? 3 : 2) ||
195
+ args.size < (block.nil? ? 1 : 0)
196
+ raise ArgumentError, "wrong number of arguments (#{args.size})"
197
+ end
198
+
199
+ val = nil
200
+ if block.nil?
201
+ val = args.shift
202
+ end
203
+
204
+ if args[0].is_a? Range
205
+ range = args[0]
206
+ if block.nil?
207
+ fill(val, range.first, range.last - range.first)
208
+ end
209
+ elsif args.size != 0
210
+ start = args[0].to_int
211
+ len = args.size == 2 ? args[1] : size
212
+ if block.nil?
213
+ args[1].times do |i|
214
+ replace_at(start + i, val)
215
+ end
216
+ else
217
+ args[1].times do |i|
218
+ index = start + i
219
+ replace_at(index, block.call(index))
220
+ end
221
+ end
222
+ else
223
+ size.times do |i|
224
+ if block.nil?
225
+ replace_at(i, val)
226
+ else
227
+ replace_at(i, block.call(i))
228
+ end
229
+ end
230
+ end
231
+ end
232
+
233
+ # Same as Array's.
234
+ # This method raises NotImplementedError
235
+ # if the class provides no insert-accessor.
236
+ def insert(nth, *val)
237
+ val.each_with_index do |el, i|
238
+ if nth > 0
239
+ insert_at(nth + i, el)
240
+ else
241
+ insert_at(nth, el)
242
+ end
243
+ end
244
+ end
245
+
246
+ # Remove specified number of elements from the last of this object.
247
+ # If the number is not specified, remove one element.
248
+ # This method ALWAYS RETURNS NULL.
249
+ def pop(*args)
250
+ if args.size > 1
251
+ raise ArgumentError, "wrong number of arguments (#{args.size})"
252
+ end
253
+
254
+ n = 1
255
+ if args.size == 1
256
+ n = args[0].to_int
257
+ end
258
+ shrink(n)
259
+ return nil
260
+ end
261
+
262
+ # Same as Array's.
263
+ # This method raises NotImplementedError
264
+ # if the class provides no size-provider.
265
+ def push(*obj)
266
+ obj.each do |el|
267
+ replace_at(size, el)
268
+ end
269
+ end
270
+
271
+ # Same as Array's.
272
+ # This method raises NotImplementedError
273
+ # if the class provides no size-provider.
274
+ def replace(another)
275
+ diff = another.size - size
276
+ shrink(-diff) if diff < 0
277
+ expand(diff) if diff > 0
278
+ another.each_with_index do |el, index|
279
+ replace_at(index, el)
280
+ end
281
+ return self
282
+ end
283
+
284
+ # Same as Array's.
285
+ # This method raises NotImplementedError
286
+ # if the class provides no delete-accessor.
287
+ def shift(*args)
288
+ if args.size > 1
289
+ raise ArgumentError, "wrong number of arguments(#{args.size})"
290
+ end
291
+
292
+ n = 1
293
+ unless args.empty?
294
+ n = args[0].to_int
295
+ end
296
+ n.times do
297
+ delete_at(0)
298
+ end
299
+ return nil
300
+ end
301
+
302
+ end
@@ -0,0 +1,3 @@
1
+ require 'test/test-random-readable'
2
+ require 'test/test-random-writable'
3
+ require 'test/test-random-accessible'
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: random-accessible
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Natsuki Kawai
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-12-03 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: ! 'RandomAccessible mixin provides all methods of Array to your classes
15
+ (regard as high-functioning edition of Enumerable).
16
+
17
+ As Enumerable mixin requests "each" method, RandomAccessible requests methods below
18
+ (or alternative, please see README.en for detail).
19
+
20
+
21
+ - size (same as Array#size)
22
+
23
+
24
+ - read_access (similar to Array#[])
25
+
26
+
27
+ - replace_access (similar to Array#[]=)
28
+
29
+
30
+ - shrink (similar to Array#pop)
31
+
32
+ '
33
+ email:
34
+ - natsuki.kawai@gmail.com
35
+ executables: []
36
+ extensions: []
37
+ extra_rdoc_files:
38
+ - README.en
39
+ files:
40
+ - lib/#random-readable.rb#
41
+ - lib/random-accessible.rb
42
+ - lib/common-traits.rb
43
+ - lib/random-writable.rb
44
+ - lib/random-readable.rb
45
+ - README.en
46
+ - test/test-suite.rb
47
+ homepage: https://github.com/natsuki14/random-accessible
48
+ licenses:
49
+ - Ruby's
50
+ - 2-clause BSDL
51
+ post_install_message:
52
+ rdoc_options: []
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubyforge_project:
69
+ rubygems_version: 1.8.12
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: RandomAccessible mixin provides all methods of Array.
73
+ test_files:
74
+ - test/test-suite.rb