webget_ramp 1.7.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data.tar.gz.sig +0 -0
  2. data/lib/webget_ramp.rb +227 -0
  3. data/lib/webget_ramp/active_record.rb +119 -0
  4. data/lib/webget_ramp/active_record/connection_adapters/abstract/schema_statements.rb +24 -0
  5. data/lib/webget_ramp/array.rb +369 -0
  6. data/lib/webget_ramp/csv.rb +52 -0
  7. data/lib/webget_ramp/date.rb +87 -0
  8. data/lib/webget_ramp/enumerable.rb +369 -0
  9. data/lib/webget_ramp/file.rb +13 -0
  10. data/lib/webget_ramp/hash.rb +195 -0
  11. data/lib/webget_ramp/integer.rb +20 -0
  12. data/lib/webget_ramp/io.rb +63 -0
  13. data/lib/webget_ramp/kernel.rb +34 -0
  14. data/lib/webget_ramp/math.rb +18 -0
  15. data/lib/webget_ramp/nil.rb +9 -0
  16. data/lib/webget_ramp/numeric.rb +94 -0
  17. data/lib/webget_ramp/object.rb +18 -0
  18. data/lib/webget_ramp/process.rb +153 -0
  19. data/lib/webget_ramp/string.rb +220 -0
  20. data/lib/webget_ramp/symbol.rb +10 -0
  21. data/lib/webget_ramp/time.rb +9 -0
  22. data/lib/webget_ramp/xml.rb +120 -0
  23. data/lib/webget_ramp/yaml.rb +32 -0
  24. data/test/webget_ramp/active_record/connection_adapters/abstract/schema_statements_test.rb +9 -0
  25. data/test/webget_ramp/active_record_test.rb +64 -0
  26. data/test/webget_ramp/array_test.rb +171 -0
  27. data/test/webget_ramp/csv_test.rb +18 -0
  28. data/test/webget_ramp/date_test.rb +60 -0
  29. data/test/webget_ramp/enumerable_test.rb +271 -0
  30. data/test/webget_ramp/file_test.rb +15 -0
  31. data/test/webget_ramp/hash_test.rb +105 -0
  32. data/test/webget_ramp/integer_test.rb +19 -0
  33. data/test/webget_ramp/io_test.rb +31 -0
  34. data/test/webget_ramp/io_test.txt +1 -0
  35. data/test/webget_ramp/kernel_test.rb +15 -0
  36. data/test/webget_ramp/math_test.rb +17 -0
  37. data/test/webget_ramp/nil_test.rb +11 -0
  38. data/test/webget_ramp/numeric_test.rb +28 -0
  39. data/test/webget_ramp/object_test.rb +12 -0
  40. data/test/webget_ramp/process_test.rb +24 -0
  41. data/test/webget_ramp/string_test.rb +125 -0
  42. data/test/webget_ramp/symbol_test.rb +26 -0
  43. data/test/webget_ramp/time_test.rb +12 -0
  44. data/test/webget_ramp/xml_test.rb +50 -0
  45. data/test/webget_ramp/xml_test_1.xml +5 -0
  46. data/test/webget_ramp/xml_test_2.xml +5 -0
  47. data/test/webget_ramp/yaml_test.rb +32 -0
  48. data/test/webget_ramp/yaml_test_1.yml +38 -0
  49. data/test/webget_ramp/yaml_test_2.yml +38 -0
  50. metadata +124 -0
  51. metadata.gz.sig +0 -0
data.tar.gz.sig ADDED
Binary file
@@ -0,0 +1,227 @@
1
+ =begin rdoc
2
+
3
+ = WebGet.com Ramp: methods to ramp up your Ruby On Rails applications
4
+
5
+ Ramp is a library of extensions to Ruby and Rails base classes, including ActiveRecord, Array, Date, Enumerable, Hash, Kernel, Numeric, Object, Process, String, Time, and YAML.
6
+
7
+
8
+ Testing:
9
+ <ul>
10
+ <li>Each has an associated test class, e.g., ArrayTest, DateTest, etc.
11
+ <li>The easy way to run the tests: gem install ramp --test
12
+ <li>Some of the ActiveRecord extensions use sqlite for testing. We don't install sqlite automatically because it requires some native extensions. If you need sqlite: gem install sqlite3-ruby
13
+ </ul>
14
+
15
+
16
+ == ActiveRecord
17
+
18
+ * create_or_update_by: create a record, or update a record if value passed matches a field (or fields) in the AR object; includes method_missing function to make code more readable.
19
+ * seed: syntactic sugar alias for #create_or_update_by
20
+
21
+
22
+ == ActiveRecord::ConnectionAdapters::SchemaStatements
23
+
24
+ * add_column_and_index: database migration helper to add a table column and index at the same time.
25
+ * remove_column_and_index: database migration helper to add a table column and index at the same time.
26
+
27
+
28
+ == Array
29
+
30
+ * car, cdr: aka first, rest (see shifted)
31
+ * choice, choices: one or more random elements from an array
32
+ * cross: return the cross pairings of an array with another array
33
+ * divvy: divides an array, like a pie, into a specified number of slices
34
+ * join: same as Array#join with some improvments
35
+ * onto: return a hash that maps an array's keys on to another array's values
36
+ * rotate: moves the first element of an array to the end
37
+ * rest: return the rest of the items of the array (aka cdr, aka shifted)
38
+ * shifted, shifted!: return an array with the first n items shifted (aka cdr, aka rest)
39
+ * shuffle, shuffle!: randomly sort an array efficiently; each of these methods are loaded only if needed (Ruby 1.8.7+ already defines shuffle)
40
+ * slices: divide an array into specified number of equal size sub-arrays ([1,2,3,4,5,6]slices(3) => [[1,2],[3,4],[5,6]])
41
+ * to_csv: join a multidimensional array into a string in CSV (Comma Separated Values), with each subarray becoming one 'line' in the output; typically for viewing in a spreadsheet such as Excel.
42
+ * to_tdf: join a multidimensional array into a string in TDF (Tab Delimited Format); this is an alias for #to_tsv
43
+ * to_tsv: join a multidimensional array into a string in TSV (Tab Separated Values), with each subarray becoming one 'line' in the output; typically for viewing in a spreadsheet such as Excel.
44
+ * union: builds an array containing each of the unique elements of sub-arrays ([[1,2,3,4],[2,3,4,5],[3,4,5,6]].union => [1,2,3,4,5,6])
45
+
46
+
47
+ == CSV
48
+
49
+ * http_headers: provides web file download headers for text/csv content type and disposition.
50
+
51
+
52
+ == Date
53
+
54
+ * age_days, age_years
55
+ * between: a random date between two specified dates
56
+ * to_sql: date as a string formatted as expected for MySQL
57
+ * weekday?, weekend?: is date a weekday or on the weekend
58
+
59
+
60
+ == Enumerable
61
+
62
+ * cartesian_product: return an array of all possible ordered tuples from arrays.
63
+ * hash_by: convert the array to a hash by mapping each item to a key=>value pair.
64
+ * index_by: convert the array to a hash by mapping each ite to a key=>item pair.
65
+ * join: forwards to self.to_a.join
66
+ * map_id: returns the id of an Enumerable object; *requires* that the object respond to an 'id' message
67
+ * map_to_a, map_to_f, map_to_i, map_to_s, map_to_sym : convert each object to a specific type by calling its respective method to_a, to_i, to_f, to_s, to_sym
68
+ * nitems_until, select_until: returns the number of, or an array containing, the leading elements for which block is false or nil.
69
+ * nitems_while, select_while: returns the number of items, or an array containing the leading elements, for which block is not false or nil.
70
+ * nitems_with_index, select_with_index: calls block with two arguments, the item and its index, for each item in enum. Returns the number of, or an array containing, the leading elements for which block is not false or nil.
71
+ * power_set: return an array with all subsets of the enum's elements
72
+
73
+
74
+ == File
75
+
76
+ * File.joindir: wrapper for File.join(File.dirname(...),string,...)
77
+
78
+
79
+ == Hash
80
+
81
+ * size?: return true if hash has any keys
82
+ * each_sort: sort the keys then call each
83
+ * each_key!: passes each key to a specified block and updates hash in place if the key changes
84
+ * each_pair!: passes each key value pair to a specified block and updates the hash in place if the key or value change.
85
+ * each_value!: passes each value to a specified block and updates the hash in place if the value changes.
86
+ * map_pair: map each key-value pair by calling a a block
87
+ * pivot: aggregates subtotals by keys and values, such as a rollup and rolldown
88
+ * to_yaml_sort: returns a YAML object, sorted by field name
89
+
90
+
91
+ == Integer
92
+
93
+ * maps: syntactic sugar to yield n times to a block, returning an array of any results (e.g. 3.maps{rand} => [0.4351325,0.7778625,0.158613534])
94
+
95
+
96
+ == IO
97
+
98
+ * readrow: reads a row line as with IO#readline, and return the row split it into fields
99
+ * IO.readrows: reads the entire file specified by name as individual row lines, and returns those rows split into fields, in an array of arrays.
100
+
101
+
102
+ == Kernel
103
+
104
+ * method_name:
105
+ * method_name_of_caller: returns the name of the method which called the current method, or the Nth parent up the call stack if the optional caller_index parameter is passed.
106
+
107
+
108
+ == Math
109
+
110
+ * ln(x): natural log of x
111
+ * logn(x,b): log of x in base b
112
+
113
+
114
+ == Numeric
115
+
116
+ * if: returns 0 if the passed flag is any of: nil, false, 0, [], {} and otherwise returns self
117
+ * unless: returns 0 unless the passed flag is any of: nil, false, 0, [], {} and otherwise returns self
118
+ * peta, tera, giga, mega, kilo, hecto, deka, deci, centi, milli, micro, nano: multiply/divide by powers of ten
119
+
120
+
121
+ == Object
122
+
123
+ * in?: returns boolean indicating whether the object is a member of the specified array parameter
124
+
125
+
126
+ == Process
127
+
128
+ Extensions that help debug Ruby programs.
129
+
130
+ * (class) ps: output of the system 'ps' command, also including aliases, as raw plain text.
131
+ * (class) pss: output of the system 'ps' command as a hash with each value set to the right type, e.g., integer, float, etc..
132
+
133
+
134
+ == REXML::Attributes
135
+
136
+ * hash: flattens the attributes hash set into a more useful ruby hash, e.g. {:height => 100, :width => 400 }
137
+
138
+
139
+ == REXML::Document
140
+
141
+ * remove_attributes: remove all the attributes from the document's elements
142
+
143
+
144
+ == REXML::Element
145
+
146
+ * remove_attributes: remove all the attributes from the element
147
+
148
+
149
+ == String
150
+
151
+ * capitalize_words (alias to titleize/titlecase): ensures the first character of each word is uppercase.
152
+ * decrement: decrease the rightmost natural number, defaults to one value lower or by the optional step parameter value.
153
+ * increment: increase the rightmost natural number, defaults to one value higher or by the optional step parameter value.
154
+ * lorem: return a short random string, good for use in "lorem ipsum" sample text.
155
+ * lowcase: translate a string to lowercase, digits and single underscores (e.g. to a method name)
156
+ * prev/pred: previous string ("b" => "a", "bbc" => "bbb", "a" => "z", "880" => "879")
157
+ * prev!/pred!: updates variable to the previous string in place (astring = "bbc", astring.prev!, puts astring => "bbb")
158
+ * (class) prev_char/pred_char: returns the previous character, with a changed flag and carry flag; that is, there are three returned values, a string and two booleans.
159
+ * split_tab: split the string into an array at each embedded tab ("Last\tFirst\tMiddle" => ["last","first","middle"])
160
+ * split_tsv: split the string into an array at each embedded newline and embedded tab ("A\tB\t\C\nD\tE\tF" => [["A","B","C"],["D","E","F"]])
161
+ * to_class: the global class reference of a given string
162
+ * words: split the string into an array of words
163
+
164
+
165
+ == Symbol
166
+
167
+ * <=> and include the comparable mixin to compare symbols as strings
168
+
169
+
170
+ == Time
171
+
172
+ * (class) stamp: current time in UTC as a timestamp string ("YYYYMMDDHHMMSS")
173
+ * to_sql: time as a string formatted as expected for MySQL
174
+
175
+
176
+ == XML
177
+
178
+ * (class) load_dir: specify a one or more directory patterns and pass each XML file in the matching directories to a block; see [Dir#glob](http://www.ruby-doc.org/core/classes/Dir.html#M002347) for pattern details.
179
+
180
+
181
+ == YAML
182
+
183
+ * (class) load_dir: specify a one or more directory patterns and pass each YAML file in the matching directories to a block; see [Dir#glob](http://www.ruby-doc.org/core/classes/Dir.html#M002347) for pattern details.
184
+
185
+
186
+ == Changes
187
+
188
+ - 1.7.1.1 Update gems: Gemcutter, Ruby 1.9.1, JRuby sqlite3
189
+ - 1.7.1.0 Add XML attributes methods #
190
+ - 1.7.0.9 Add Enumerable #hash_by, #index_by
191
+ - 1.7.0.7 Add Array#to_tsv, String#split_tsv, improve Array#to_csv
192
+ - 1.7.0.6 Add Array#shuffle, Array#shuffle!
193
+ - 1.7.0.5 Add Array#shifted, Array#rest, Array#car, Array#cdr
194
+ - 1.7.0.4 Upgrade IO#readrows and #readrow to use options
195
+ - 1.7.0.2 Add Array#to_tdf
196
+ - 1.7.0.1 Remove sqlite3 testing dependency
197
+ - 1.6.9.6 Add Symbol with comparable and <=>
198
+ - 1.6.9.5 Add ActiveRecord testing with sqlite3
199
+ - 1.6.9.4 JRuby install and test successful
200
+ - 1.6.9.3 Array#join add infix, prefix, suffix
201
+ - 1.6.9.2 Improve ri docs
202
+ - 1.6.9.1 Add Array#onto, Enumerable#intersect?
203
+ - 1.6.9.0 Add IO, File, ActiveRecord#seed
204
+ - 1.6.8.9 Add Enumerable#to_h, Array#hash, Hash#each_key!, Hash#each_pair, Hash#each_value!
205
+ - 1.6.8.8 Add Hash#map_pair, Hash#size?, Hash#pivot
206
+ - 1.6.8.7 Add Math
207
+ - 1.6.8.6 Add ActiveRecord SchemaStatements
208
+ - 1.6.8.5 Add Integer#maps, String#ACCENTS
209
+ - 1.6.8.4 Add XML
210
+ - 1.6.8.3 Add ActiveRecord
211
+ - 1.6.8.2 Add String#lowcase
212
+ - 1.6.8 Add map_to_xxx methods
213
+ - 1.6.7 Add CSV
214
+ - 1.6.6 Add Array#to_csv, Integer, String#lorem, etc., improve tests
215
+ - 1.6.4 Bug fixes: String characters and YAML test files
216
+ - 1.6.2 Improve organizaiton of class files to lib/ramp
217
+ - 1.6.0 Upgraded to work with Ruby 1.9.1
218
+ - 1.5.0 Combined all Ruby extension files into one gem
219
+ - 1.0.0 Original
220
+
221
+ =end
222
+
223
+ %w{active_record array csv date enumerable file hash integer io kernel math nil numeric object process string symbol time xml yaml}.map{|x|
224
+ require File.dirname(__FILE__) + "/webget_ramp/#{x}.rb"
225
+ }
226
+
227
+
@@ -0,0 +1,119 @@
1
+ require 'activerecord'
2
+ require 'active_record'
3
+
4
+ #:startdoc:
5
+ # ActiveRecord extensions
6
+
7
+ module ActiveRecord #:doc:
8
+
9
+ class Base #:doc:
10
+
11
+ # Create a record, or update a record if value passed matches a field in the AR object;
12
+ # includes method_missing function to make code more readable
13
+ #
14
+ # Most common use will be for testing (fixture/mock object generation)
15
+ #
16
+ # Three versions of method included:
17
+ # create_or_update
18
+ # create_or_update_by
19
+ # create_or_update_by_xxx (where xxx is a field name)
20
+ #
21
+ # Inspired by http://www.intridea.com/2008/2/19/activerecord-base-create_or_update-on-steroids-2
22
+ #
23
+ # ==Example
24
+ # { "admin" => ["Administrator", 1000],
25
+ # "member" => ["Member", 1],
26
+ # "moderator" => ["Moderator", 100],
27
+ # "disabled" => ["Disabled User", -1] }.each_pair do |key, val|
28
+ # Role.create_or_update_by_key(:key => key, :name => val[0], :value => val[1])
29
+ # end
30
+
31
+ def self.create_or_update(options = {})
32
+ self.create_or_update_by(:id, options)
33
+ end
34
+
35
+
36
+ # Create or update a record by field (or fields).
37
+ # This will look for each field name as a key in the options hash.
38
+ #
39
+ # ==Example
40
+ # attributes={:name="John Smith", :email=>"john@example.com", :birthdate=>'1980/01/01'}
41
+ # User.create_or_update_by(:email,attributes)
42
+ # => if a user with that email exists then update his name and birthdate, else create him
43
+ #
44
+ # ==Example with multiple conditions
45
+ # attributes={:name="John Smith", :email=>"john@example.com", :birthdate=>'1980/01/01'}
46
+ # User.create_or_update_by([:name,:birthdate],attributes)
47
+ # => if a user with that name and birthdate exists then update his email, else create him
48
+ #
49
+ # The fields can be any mix of symbols or strings.
50
+ # The option keys can be any mix of symbols or strings.
51
+
52
+ def self.create_or_update_by(condition_keys, attribute_pairs = {})
53
+ condition_pairs=[*condition_keys].map{|x| [x,(attribute_pairs.delete(x)||attribute_pairs.delete(x.to_s)||attribute_pairs.delete(x.to_sym))]}.to_h
54
+ record = find(:first, :conditions => condition_pairs) || self.new
55
+ if record.new_record? then attribute_pairs.merge!(condition_pairs) end
56
+ attribute_pairs.each_pair{|k,v| record.send k.to_s+'=', v}
57
+ record.save!
58
+ return record
59
+ end
60
+
61
+
62
+ # Set up a database with initial data, e.g. in rake db:seed method.
63
+ #
64
+ # This will look for each field name as a key in the options hash.
65
+ #
66
+ # This method calls #create_or_update_by (and you may want to change
67
+ # this behavior to do more, e.g. to test that a DB and table exists).
68
+ #
69
+ # ==Example
70
+ # attributes={:name="John Smith", :email=>"john@example.com", :birthdate=>'1980/01/01'}
71
+ # User.create_or_update_by(:email,attributes)
72
+ # => if a user with that email exists then update his name and birthdate, else create him
73
+ #
74
+ # ==Example with multiple conditions
75
+ # attributes={:name="John Smith", :email=>"john@example.com", :birthdate=>'1980/01/01'}
76
+ # User.create_or_update_by([:name,:birthdate],attributes)
77
+ # => if a user with that name and birthdate exists then update his email, else create him
78
+ #
79
+ # The fields can be any mix of symbols or strings.
80
+ # The option keys can be any mix of symbols or strings.
81
+
82
+ def self.seed(condition_keys, attribute_pairs = {})
83
+ self.create_or_update_by(condition_keys, attribute_pairs)
84
+ end
85
+
86
+
87
+ # Method missing for create_or_update_by_xxx that forwards to #create_or_update_by
88
+ #
89
+ # ==Example
90
+ # MyModel.create_or_update_by_foo(options)
91
+ # => MyModel.create_or_update_by(:foo,option)
92
+
93
+ def self.method_missing_with_create_or_update(method_name, *args)
94
+ if match = method_name.to_s.match(/create_or_update_by_([a-z0-9_]+)/)
95
+ field = match[1]
96
+ return create_or_update_by(field,*args)
97
+ end
98
+ return method_missing_without_create_or_update(method_name, *args)
99
+ end
100
+
101
+
102
+ # For alias method chain
103
+ def self.included(base)
104
+ # base == ActiveRecord::Base (the class)
105
+ base.class_eval do
106
+ # class_eval makes self == ActiveRecord::Base, and makes def define instance methods.
107
+ extend ClassMethods
108
+ # If has_many were an instance method, we could do this
109
+ # alias_method_chain :has_many, :association_option; end
110
+ # but it's a class method, so we have to do the alias_method_chain on
111
+ # the meta-class for ActiveRecord::Base, which is what class << self does.
112
+ class << self; alias_method_chain :method_missing, :create_or_update; end
113
+ end
114
+ end
115
+
116
+
117
+ end
118
+
119
+ end
@@ -0,0 +1,24 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module SchemaStatements
4
+
5
+ # Add a column and its index.
6
+ # This just calls #add_column then #add_index
7
+
8
+ def add_column_and_index(table_name, column_name, type, options = {})
9
+ add_column(table_name, column_name, type, options)
10
+ add_index(table_name, column_name, type, options)
11
+ end
12
+
13
+
14
+ # Remove a column and its index in one step.
15
+ # This just calls #remove_column then #remove_index.
16
+
17
+ def remove_column_and_index(table_name, column_name, type, options = {})
18
+ remove_column(table_name, column_name, type, options)
19
+ remove_index(table_name, column_name, type, options)
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,369 @@
1
+ require 'csv'
2
+
3
+
4
+ class Array
5
+
6
+
7
+ # Alias join because we're going to override it
8
+
9
+ alias :ruby_join :join
10
+
11
+
12
+ # Concatenate the items into a string by join.
13
+ #
14
+ # ==Typical Array#join with infix
15
+ # list=['a','b','c']
16
+ # list.join("*") => "a*b*c"
17
+ #
18
+ # ==Improved join with infix, prefix, suffix
19
+ # list=['a','b','c']
20
+ # list.join("*","[","]") => "[a]*[b]*[c]"
21
+ #
22
+ # ==Improved join with just prefix and suffix
23
+ # list=['a','b','c']
24
+ # list.join("[","]") => "[a][b][c]"
25
+
26
+ def join(*fixes)
27
+ if fixes.is_a?(String) then return self.ruby_join(fixes) end
28
+ case fixes.size
29
+ when 0
30
+ return self.ruby_join()
31
+ when 1
32
+ return self.ruby_join(fixes[0])
33
+ when 2
34
+ prefix=fixes[0].to_s
35
+ suffix=fixes[1].to_s
36
+ return self.map{|s| prefix + s.to_s + suffix}.ruby_join()
37
+ when 3
38
+ infix =fixes[0].to_s
39
+ prefix=fixes[1].to_s
40
+ suffix=fixes[2].to_s
41
+ return map{|s| prefix + s.to_s + suffix}.ruby_join(infix)
42
+ else
43
+ raise "join(fixes[#{fixes.size}]"
44
+ end
45
+ end
46
+
47
+
48
+ # Return true if size > 0
49
+ #
50
+ # ==Examples
51
+ # [1,2,3].size? => true
52
+ # [].size? => false
53
+
54
+ def size?
55
+ return size>0
56
+ end
57
+
58
+
59
+ # Move the first item to the last by using Array#shift and Array#push
60
+ #
61
+ # ==Examples
62
+ # [1,2,3,4].rotate! => [2,3,4,1]
63
+ # ['a','b','c'].rotate! => ['b','c','a']
64
+ #
65
+ # Return self
66
+
67
+ def rotate!
68
+ push x=shift
69
+ self
70
+ end
71
+
72
+
73
+ # Return a random item from the array
74
+ #
75
+ # ==Examples
76
+ # [1,2,3,4].choice => 2
77
+ # [1,2,3,4].choice => 4
78
+ # [1,2,3,4].choice => 3
79
+ #
80
+ # Implemented in Ruby 1.9
81
+
82
+ def choice
83
+ self[Kernel.rand(size)]
84
+ end
85
+
86
+
87
+ # Return a new array filled with _n_ calls to choice
88
+ #
89
+ # ==Examples
90
+ # [1,2,3,4].choices(2) => [3,1]
91
+ # [1,2,3,4].choices(3) => [4,2,3]
92
+
93
+ def choices(n)
94
+ a = Array.new
95
+ n.times { a << self.choice }
96
+ return a
97
+ end
98
+
99
+
100
+ # Return a hash of this array's items as keys
101
+ # mapped onto another array's items as values.
102
+ #
103
+ # ==Example
104
+ # foo=[:a,:b,:c]
105
+ # goo=[:x,:y,:z]
106
+ # foo.onto(goo) => {:a=>:x, :b=>:y, :c=>:z}
107
+ #
108
+ # This is identical to calling foo.zip(values).to_h
109
+
110
+ def onto(values)
111
+ zip(values).to_h
112
+ end
113
+
114
+
115
+ ##############################################################
116
+ #
117
+ # GROUPINGS
118
+ #
119
+ ##############################################################
120
+
121
+
122
+ # Return items in groups of _n_ items (aka slices)
123
+ #
124
+ # ==Examples
125
+ # [1,2,3,4,5,6,7,8].slices(2) => [[1,2],[3,4],[5,6],[7,8]]
126
+ # [1,2,3,4,5,6,7,8].slices(4) => [[1,2,3,4],[5,6,7,8]]
127
+ #
128
+ # If the slices don't divide evenly, then the last is smaller.
129
+ #
130
+ # ==Examples
131
+ # [1,2,3,4,5,6,7,8].slices(3) => [[1,2,3],[4,5,6],[7,8]]
132
+ # [1,2,3,4,5,6,7,8].slices(5) => [[1,2,3,4,5],[6,7,8]]
133
+
134
+ def slices(slice_length)
135
+ a=[]
136
+ i=0
137
+ while i<length
138
+ a.push self[i...(i+slice_length)]
139
+ i+=slice_length
140
+ end
141
+ return a
142
+ end
143
+
144
+
145
+ # Divvy the array, like a pie, into _n_ number of slices.
146
+ #
147
+ # If the array divides evenly, then each slice has size/n items.
148
+ #
149
+ # Otherwise, divvy makes a best attempt by rounding up to give
150
+ # earlier slices one more item, which makes the last slice smaller:
151
+ #
152
+ # ==Examples
153
+ # [1,2,3,4,5].divvy(2) => [[1,2,3],[4,5]]
154
+ # [1,2,3,4,5,6,7].divvy(3) => [[1,2,3],[4,5,6],[7]]
155
+ #
156
+ # If the array size so small compared to _n_ that there is
157
+ # no mathematical way to _n_ slices, then divvy will return
158
+ # as many slices as it can.
159
+ #
160
+ # ==Examples
161
+ # [1,2,3,4,5,6].divvy(4) => [[1,2],[3,4],[5,6]]
162
+
163
+ def divvy(number_of_slices)
164
+ return slices((length.to_f/number_of_slices.to_f).ceil)
165
+ end
166
+
167
+
168
+ ##############################################################
169
+ #
170
+ # COMBINATIONS
171
+ #
172
+ ##############################################################
173
+
174
+
175
+ # Return the union of the array's items.
176
+ # In typical use, each item is an array.
177
+ #
178
+ # ==Example using Ruby Array pipe
179
+ # a=[1,2,3]
180
+ # b=[2,3,4]
181
+ # a | b => [1,2,3,4]
182
+ #
183
+ # ==Example using union method
184
+ # arr=[a,b]
185
+ # => [1,2,3,4]
186
+ #
187
+ # This is identical to
188
+
189
+ # ==Examples with proc
190
+ # arr.map(&:foo).union
191
+ # => foos that are in any of the array items
192
+
193
+ def union
194
+ inject{|inj,x| inj | x.to_a }
195
+ end
196
+
197
+
198
+ # Return the intersection of the array's items.
199
+ # In typical usage, each item is an array.
200
+ #
201
+ # ==Examples
202
+ # arr=[[1,2,3,4],[2,3,4,5],[3,4,5,6]]
203
+ # arr.intersect
204
+ # => [3,4]
205
+ #
206
+ # ==Examples with proc
207
+ # arr.map(&:foo).intersect
208
+ # => foos that are in all of the array items
209
+
210
+ def intersect
211
+ inject{|inj,x| inj & x.to_a }
212
+ end
213
+
214
+
215
+
216
+ ##############################################################
217
+ #
218
+ # LIST PROCESSING
219
+ #
220
+ ##############################################################
221
+
222
+ # Returns the rest of the items of self, after a shift.
223
+ #
224
+ # ==Example
225
+ # list=['a','b','c']
226
+ # list.shift => 'a'
227
+ # list.shifted => ['b','c']
228
+ #
229
+ # ==Example with length
230
+ # list.shifted(0) => ['a','b','c']
231
+ # list.shifted(1) => ['b','c']
232
+ # list.shifted(2) => ['c']
233
+ # list.shifted(3) => []
234
+ #
235
+ # Ruby programmers may prefer this alias wording:
236
+ # list.first => 'a'
237
+ # list.rest => ['b','c']
238
+ #
239
+ # LISP programmers may prefer this alias wording:
240
+ # list.car => 'a'
241
+ # list.cdr => ['b','c']
242
+ #
243
+
244
+ def shifted(n=1)
245
+ slice(n,self.length-n)
246
+ end
247
+
248
+ alias :car :first
249
+ alias :cdr :shifted
250
+ alias :rest :shifted
251
+
252
+
253
+ # Delete the first _n_ items. Returns the array, not the deleted items.
254
+ #
255
+ # ==Example
256
+ # list=['a','b','c']
257
+ # list.shifted!
258
+ # list => ['b','c']
259
+ #
260
+ # ==Example with length:
261
+ # list=['a','b','c']
262
+ # list.shifted!(2)
263
+ # list => ['c']
264
+ #
265
+ # If _n_ is greater than the array size, then return []
266
+
267
+ def shifted!(n=1)
268
+ slice!(0,n)
269
+ return self
270
+ end
271
+
272
+ alias :cdr! :shifted!
273
+ alias :rest! :shifted!
274
+
275
+
276
+ # Randomly arrange the array items.
277
+ #
278
+ # This implementation is optimized for speed, not for memory use.
279
+ # See http://codeidol.com/other/rubyckbk/Arrays/Shuffling-an-Array/
280
+ #
281
+ # This method definition is skipped if Array#shuffle! is already defined.
282
+ #
283
+ # ==Example
284
+ # list=
285
+ # list=['a','b','c']
286
+ # list.shuffle!
287
+ # list => ['c','a','b']
288
+
289
+ if !instance_methods.include?('shuffle!')
290
+ def shuffle!
291
+ each_index do |i|
292
+ j = rand(length-i) + i
293
+ self[j], self[i] = self[i], self[j]
294
+ end
295
+ end
296
+ end
297
+
298
+ # Return the array items in random order.
299
+ #
300
+ # This implementation is optimized for speed, not for memory use.
301
+ # See http://codeidol.com/other/rubyckbk/Arrays/Shuffling-an-Array/
302
+ #
303
+ # This method definition is skipped if Array#shuffle is already defined.
304
+ # For example, Ruby 1.8.7 Array#shuffle is already defined.
305
+ #
306
+ # ==Example
307
+ # list=
308
+ # list=['a','b','c']
309
+ # list.shuffle!
310
+ # list => ['c','a','b']
311
+
312
+ if !instance_methods.include?('shuffle') and instance_methods.include?('shuffle!')
313
+ def shuffle
314
+ dup.shuffle!
315
+ end
316
+ end
317
+
318
+
319
+ ##############################################################
320
+ #
321
+ # CASTS
322
+ #
323
+ ##############################################################
324
+
325
+ # Returns a CSV (Comma Separated Value) string of this array.
326
+ #
327
+ # ==Example of a one-dimensional array
328
+ #
329
+ # [1,2,3].to_csv => "1,2,3\n"
330
+ #
331
+ # ==Example of a multi-dimensional array
332
+ #
333
+ # [[1,2,3],[4,5,6]] => "1,2,3\n4,5,6\n"
334
+ #
335
+ # N.b. this method uses the multi-dimensional if the
336
+ # array's first item is also an array.
337
+
338
+ def to_csv(ops={})
339
+
340
+ generator = RUBY_VERSION >= "1.9" ? CSV : CSV::Writer
341
+
342
+ s=''
343
+ if size>0 and self[0].is_a?Array
344
+ generator.generate(s) do |csv|
345
+ self.each do |row|
346
+ csv << row
347
+ end
348
+ end
349
+ else
350
+ generator.generate(s) do |csv|
351
+ csv << self.map{|x| x.to_s}
352
+ end
353
+ end
354
+ return s
355
+ end
356
+
357
+
358
+ # Returns a TSV (Tab Separated Value) string
359
+ # representation of a multi-dimensional array.
360
+ #
361
+ # Each subarray becomes one 'line' in the output.
362
+
363
+ def to_tsv(ops={})
364
+ self.map{|row| row.join("\t")+"\n"}.join
365
+ end
366
+
367
+ alias to_tdf to_tsv
368
+
369
+ end