webget_ruby_ramp 1.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data.tar.gz.sig +0 -0
  2. data/lib/webget_ruby_ramp.rb +250 -0
  3. data/lib/webget_ruby_ramp/active_record.rb +119 -0
  4. data/lib/webget_ruby_ramp/active_record/connection_adapters/abstract/schema_statements.rb +24 -0
  5. data/lib/webget_ruby_ramp/active_record/save_extensions.rb +35 -0
  6. data/lib/webget_ruby_ramp/array.rb +370 -0
  7. data/lib/webget_ruby_ramp/csv.rb +53 -0
  8. data/lib/webget_ruby_ramp/date.rb +90 -0
  9. data/lib/webget_ruby_ramp/enumerable.rb +385 -0
  10. data/lib/webget_ruby_ramp/file.rb +15 -0
  11. data/lib/webget_ruby_ramp/hash.rb +223 -0
  12. data/lib/webget_ruby_ramp/integer.rb +22 -0
  13. data/lib/webget_ruby_ramp/io.rb +65 -0
  14. data/lib/webget_ruby_ramp/kernel.rb +36 -0
  15. data/lib/webget_ruby_ramp/math.rb +20 -0
  16. data/lib/webget_ruby_ramp/nil.rb +17 -0
  17. data/lib/webget_ruby_ramp/numeric.rb +98 -0
  18. data/lib/webget_ruby_ramp/object.rb +20 -0
  19. data/lib/webget_ruby_ramp/process.rb +153 -0
  20. data/lib/webget_ruby_ramp/string.rb +221 -0
  21. data/lib/webget_ruby_ramp/symbol.rb +11 -0
  22. data/lib/webget_ruby_ramp/time.rb +11 -0
  23. data/lib/webget_ruby_ramp/xml.rb +193 -0
  24. data/lib/webget_ruby_ramp/yaml.rb +34 -0
  25. data/test/webget_ruby_ramp/active_record/connection_adapters/abstract/schema_statements_test.rb +9 -0
  26. data/test/webget_ruby_ramp/active_record/save_extensions_test.rb +7 -0
  27. data/test/webget_ruby_ramp/active_record_test.rb +64 -0
  28. data/test/webget_ruby_ramp/array_test.rb +171 -0
  29. data/test/webget_ruby_ramp/csv_test.rb +18 -0
  30. data/test/webget_ruby_ramp/date_test.rb +60 -0
  31. data/test/webget_ruby_ramp/enumerable_test.rb +275 -0
  32. data/test/webget_ruby_ramp/file_test.rb +15 -0
  33. data/test/webget_ruby_ramp/hash_test.rb +105 -0
  34. data/test/webget_ruby_ramp/integer_test.rb +19 -0
  35. data/test/webget_ruby_ramp/io_test.rb +31 -0
  36. data/test/webget_ruby_ramp/io_test.txt +1 -0
  37. data/test/webget_ruby_ramp/kernel_test.rb +15 -0
  38. data/test/webget_ruby_ramp/math_test.rb +17 -0
  39. data/test/webget_ruby_ramp/nil_test.rb +15 -0
  40. data/test/webget_ruby_ramp/numeric_test.rb +28 -0
  41. data/test/webget_ruby_ramp/object_test.rb +12 -0
  42. data/test/webget_ruby_ramp/process_test.rb +24 -0
  43. data/test/webget_ruby_ramp/string_test.rb +125 -0
  44. data/test/webget_ruby_ramp/symbol_test.rb +26 -0
  45. data/test/webget_ruby_ramp/time_test.rb +12 -0
  46. data/test/webget_ruby_ramp/xml_test.rb +93 -0
  47. data/test/webget_ruby_ramp/xml_test_1.xml +5 -0
  48. data/test/webget_ruby_ramp/xml_test_2.xml +5 -0
  49. data/test/webget_ruby_ramp/xml_test_msword_clean.html +1 -0
  50. data/test/webget_ruby_ramp/xml_test_msword_dirty.html +148 -0
  51. data/test/webget_ruby_ramp/yaml_test.rb +32 -0
  52. data/test/webget_ruby_ramp/yaml_test_1.yml +38 -0
  53. data/test/webget_ruby_ramp/yaml_test_2.yml +38 -0
  54. metadata +128 -0
  55. metadata.gz.sig +1 -0
data.tar.gz.sig ADDED
Binary file
@@ -0,0 +1,250 @@
1
+ =begin rdoc
2
+
3
+ = WebGet Ruby Gem: Ramp is a toolkit of methods to ramp up your Ruby On Rails applications
4
+
5
+ Author:: Joel Parker Henderson, joelparkerhenderson@gmail.com
6
+ Copyright:: Copyright (c) 2006-2010 Joel Parker Henderson
7
+ License:: CreativeCommons License, Non-commercial Share Alike
8
+ License:: LGPL, GNU Lesser General Public License
9
+
10
+ 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.
11
+
12
+ Testing:
13
+ <ul>
14
+ <li>Each has an associated test class, e.g., ArrayTest, DateTest, etc.
15
+ <li>The easy way to run the tests: gem install ramp --test
16
+ <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
17
+ </ul>
18
+
19
+
20
+ == ActiveRecord
21
+
22
+ * 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.
23
+ * seed: syntactic sugar alias for #create_or_update_by
24
+
25
+
26
+ == ActiveRecord::ConnectionAdapters::SchemaStatements
27
+
28
+ * add_column_and_index: database migration helper to add a table column and index at the same time.
29
+ * remove_column_and_index: database migration helper to add a table column and index at the same time.
30
+
31
+
32
+ == ActiveRecord::SaveExtensions
33
+
34
+ * save_false_then_reload!: a transaction to save and reload a record, to help repair associations
35
+
36
+
37
+ == Array
38
+
39
+ * car, cdr: aka first, rest (see shifted)
40
+ * choice, choices: one or more random elements from an array
41
+ * cross: return the cross pairings of an array with another array
42
+ * divvy: divides an array, like a pie, into a specified number of slices
43
+ * join: same as Array#join with some improvments
44
+ * onto: return a hash that maps an array's keys on to another array's values
45
+ * rotate: moves the first element of an array to the end
46
+ * rest: return the rest of the items of the array (aka cdr, aka shifted)
47
+ * shifted, shifted!: return an array with the first n items shifted (aka cdr, aka rest)
48
+ * shuffle, shuffle!: randomly sort an array efficiently; each of these methods are loaded only if needed (Ruby 1.8.7+ already defines shuffle)
49
+ * 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]])
50
+ * 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.
51
+ * to_tdf: join a multidimensional array into a string in TDF (Tab Delimited Format); this is an alias for #to_tsv
52
+ * 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.
53
+ * 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])
54
+
55
+
56
+ == CSV
57
+
58
+ * http_headers: provides web file download headers for text/csv content type and disposition.
59
+
60
+
61
+ == Date
62
+
63
+ * age_days, age_years
64
+ * between: a random date between two specified dates
65
+ * to_sql: date as a string formatted as expected for MySQL
66
+ * weekday?, weekend?: is date a weekday or on the weekend
67
+
68
+
69
+ == Enumerable
70
+
71
+ * cartesian_product: return an array of all possible ordered tuples from arrays.
72
+ * hash_by: convert the array to a hash by mapping each item to a key=>value pair.
73
+ * index_by: convert the array to a hash by mapping each ite to a key=>item pair.
74
+ * join: forwards to self.to_a.join
75
+ * map_id: returns the id of an Enumerable object; *requires* that the object respond to an 'id' message
76
+ * 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
77
+ * map_with_index: for each item, yield to a block with the item and its incrementing index
78
+ * nitems_until, select_until: returns the number of, or an array containing, the leading elements for which block is false or nil.
79
+ * nitems_while, select_while: returns the number of items, or an array containing the leading elements, for which block is not false or nil.
80
+ * 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.
81
+ * power_set: return an array with all subsets of the enum's elements
82
+
83
+
84
+ == File
85
+
86
+ * File.joindir: wrapper for File.join(File.dirname(...),string,...)
87
+
88
+
89
+ == Hash
90
+
91
+ * size?: return true if hash has any keys
92
+ * each_sort: sort the keys then call each
93
+ * each_key!: passes each key to a specified block and updates hash in place if the key changes
94
+ * each_pair!: passes each key value pair to a specified block and updates the hash in place if the key or value change.
95
+ * each_value!: passes each value to a specified block and updates the hash in place if the value changes.
96
+ * map_pair: map each key-value pair by calling a a block
97
+ * pivot: aggregates subtotals by keys and values, such as a rollup and rolldown
98
+ * to_yaml_sort: returns a YAML object, sorted by field name
99
+
100
+
101
+ == Integer
102
+
103
+ * 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])
104
+
105
+
106
+ == IO
107
+
108
+ * readrow: reads a row line as with IO#readline, and return the row split it into fields
109
+ * 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.
110
+
111
+
112
+ == Kernel
113
+
114
+ * method_name:
115
+ * 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.
116
+
117
+
118
+ == Math
119
+
120
+ * ln(x): natural log of x
121
+ * logn(x,b): log of x in base b
122
+
123
+
124
+ == NilClass
125
+
126
+ * blank?: return true (same as Rails)
127
+
128
+
129
+ == Numeric
130
+
131
+ * if: returns 0 if the passed flag is any of: nil, false, 0, [], {} and otherwise returns self
132
+ * unless: returns 0 unless the passed flag is any of: nil, false, 0, [], {} and otherwise returns self
133
+ * peta, tera, giga, mega, kilo, hecto, deka, deci, centi, milli, micro, nano: multiply/divide by powers of ten
134
+
135
+
136
+ == Object
137
+
138
+ * in?: returns boolean indicating whether the object is a member of the specified array parameter
139
+
140
+
141
+ == Process
142
+
143
+ Extensions that help debug Ruby programs.
144
+
145
+ * (class) ps: output of the system 'ps' command, also including aliases, as raw plain text.
146
+ * (class) pss: output of the system 'ps' command as a hash with each value set to the right type, e.g., integer, float, etc..
147
+
148
+
149
+ == REXML::Attributes
150
+
151
+ * hash: flattens the attributes hash set into a more useful ruby hash, e.g. {:height => 100, :width => 400 }
152
+
153
+
154
+ == REXML::Document
155
+
156
+ * remove_attributes: remove all the attributes from the document's elements
157
+
158
+
159
+ == REXML::Element
160
+
161
+ * remove_attributes: remove all the attributes from the element
162
+
163
+
164
+ == String
165
+
166
+ * capitalize_words (alias to titleize/titlecase): ensures the first character of each word is uppercase.
167
+ * decrement: decrease the rightmost natural number, defaults to one value lower or by the optional step parameter value.
168
+ * increment: increase the rightmost natural number, defaults to one value higher or by the optional step parameter value.
169
+ * lorem: return a short random string, good for use in "lorem ipsum" sample text.
170
+ * lowcase: translate a string to lowercase, digits and single underscores (e.g. to a method name)
171
+ * prev/pred: previous string ("b" => "a", "bbc" => "bbb", "a" => "z", "880" => "879")
172
+ * prev!/pred!: updates variable to the previous string in place (astring = "bbc", astring.prev!, puts astring => "bbb")
173
+ * (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.
174
+ * split_tab: split the string into an array at each embedded tab ("Last\tFirst\tMiddle" => ["last","first","middle"])
175
+ * 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"]])
176
+ * to_class: the global class reference of a given string
177
+ * words: split the string into an array of words
178
+
179
+
180
+ == Symbol
181
+
182
+ * <=> and include the comparable mixin to compare symbols as strings
183
+
184
+
185
+ == Time
186
+
187
+ * (class) stamp: current time in UTC as a timestamp string ("YYYYMMDDHHMMSS")
188
+ * to_sql: time as a string formatted as expected for MySQL
189
+
190
+
191
+ == XML
192
+
193
+ * (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.
194
+ * (class) strip_all: delete exraneous junk from an XML text string, typically for sanitizing input
195
+ * (class) strip_attributes: delete all attributes from an XML text string
196
+ * (class) strip_comments: delete all comments from an XML text string
197
+ * (class) strip_microsoft: delete all proprietary Microsoft code from an XML text string
198
+ * (class) strip_unprintables: delete all unprintable characters from an XML text string
199
+
200
+
201
+ == YAML
202
+
203
+ * (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.
204
+
205
+
206
+ == Changes
207
+
208
+ - 1.7.2 Genmcutter update
209
+ - 1.7.1.8 Add Enumerable#map_with_index
210
+ - 1.7.1.6 Add ActiveRecord::SaveExtensions#save_false_then_reload!
211
+ - 1.7.1.3 Add XML#strip_xxx
212
+ - 1.7.1.2 Update gems: Gemcutter, Ruby 1.9.1, JRuby sqlite3
213
+ - 1.7.1.0 Add XML attributes methods #
214
+ - 1.7.0.9 Add Enumerable #hash_by, #index_by
215
+ - 1.7.0.7 Add Array#to_tsv, String#split_tsv, improve Array#to_csv
216
+ - 1.7.0.6 Add Array#shuffle, Array#shuffle!
217
+ - 1.7.0.5 Add Array#shifted, Array#rest, Array#car, Array#cdr
218
+ - 1.7.0.4 Upgrade IO#readrows and #readrow to use options
219
+ - 1.7.0.2 Add Array#to_tdf
220
+ - 1.7.0.1 Remove sqlite3 testing dependency
221
+ - 1.6.9.6 Add Symbol with comparable and <=>
222
+ - 1.6.9.5 Add ActiveRecord testing with sqlite3
223
+ - 1.6.9.4 JRuby install and test successful
224
+ - 1.6.9.3 Array#join add infix, prefix, suffix
225
+ - 1.6.9.2 Improve ri docs
226
+ - 1.6.9.1 Add Array#onto, Enumerable#intersect?
227
+ - 1.6.9.0 Add IO, File, ActiveRecord#seed
228
+ - 1.6.8.9 Add Enumerable#to_h, Array#hash, Hash#each_key!, Hash#each_pair, Hash#each_value!
229
+ - 1.6.8.8 Add Hash#map_pair, Hash#size?, Hash#pivot
230
+ - 1.6.8.7 Add Math
231
+ - 1.6.8.6 Add ActiveRecord SchemaStatements
232
+ - 1.6.8.5 Add Integer#maps, String#ACCENTS
233
+ - 1.6.8.4 Add XML
234
+ - 1.6.8.3 Add ActiveRecord
235
+ - 1.6.8.2 Add String#lowcase
236
+ - 1.6.8 Add map_to_xxx methods
237
+ - 1.6.7 Add CSV
238
+ - 1.6.6 Add Array#to_csv, Integer, String#lorem, etc., improve tests
239
+ - 1.6.4 Bug fixes: String characters and YAML test files
240
+ - 1.6.2 Improve organizaiton of class files to lib/ramp
241
+ - 1.6.0 Upgraded to work with Ruby 1.9.1
242
+ - 1.5.0 Combined all Ruby extension files into one gem
243
+ - 1.0.0 Original
244
+
245
+ =end
246
+
247
+ %w{active_record active_record/save_extensions array csv date enumerable file hash integer io kernel math nil numeric object process string symbol time xml yaml}.map{|x|
248
+ require File.dirname(__FILE__) + "/webget_ruby_ramp/#{x}.rb"
249
+ }
250
+
@@ -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{|key| [key,(attribute_pairs.delete(key)||attribute_pairs.delete(key.to_s)||attribute_pairs.delete(key.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{|key,val| record.send key.to_s+'=', val}
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,35 @@
1
+ module ActiveRecord::SaveExtensions
2
+
3
+ # Save the record without validation, then reload it.
4
+ # If the record is valid then return true, otherwise raise RecordInvalid.
5
+ # This solves an issue we found with Rails associations not saving.
6
+ #
7
+ # By Andrew Carpenter (acarpen@wested.org)
8
+ #
9
+ # Deprecated, superceded by #save_redux!
10
+
11
+ def save_false_then_reload!
12
+ transaction do
13
+ save(false)
14
+ reload
15
+ valid? or raise ActiveRecord::RecordInvalid.new(self)
16
+ end
17
+ return true
18
+ end
19
+
20
+
21
+ # Save the record without validation, then reload, then save with validtion.
22
+ # This ensure that rails brings back the correct associations to validate.
23
+ # This solves an issue we found with Rails associations not saving.
24
+
25
+ def save_redux!
26
+ transaction do
27
+ save(false)
28
+ reload
29
+ save!
30
+ end
31
+ return true
32
+ end
33
+
34
+ end
35
+ ActiveRecord::Base.send(:include, ActiveRecord::SaveExtensions)
@@ -0,0 +1,370 @@
1
+ require 'csv'
2
+
3
+ # Array extensions
4
+
5
+ class Array
6
+
7
+
8
+ # Alias join because we're going to override it
9
+
10
+ alias :ruby_join :join
11
+
12
+
13
+ # Concatenate the items into a string by join.
14
+ #
15
+ # ==Typical Array#join with infix
16
+ # list=['a','b','c']
17
+ # list.join("*") => "a*b*c"
18
+ #
19
+ # ==Improved join with infix, prefix, suffix
20
+ # list=['a','b','c']
21
+ # list.join("*","[","]") => "[a]*[b]*[c]"
22
+ #
23
+ # ==Improved join with just prefix and suffix
24
+ # list=['a','b','c']
25
+ # list.join("[","]") => "[a][b][c]"
26
+
27
+ def join(*fixes)
28
+ if fixes.is_a?(String) then return self.ruby_join(fixes) end
29
+ case fixes.size
30
+ when 0
31
+ return self.ruby_join()
32
+ when 1
33
+ return self.ruby_join(fixes[0])
34
+ when 2
35
+ prefix=fixes[0].to_s
36
+ suffix=fixes[1].to_s
37
+ return self.map{|s| prefix + s.to_s + suffix}.ruby_join()
38
+ when 3
39
+ infix =fixes[0].to_s
40
+ prefix=fixes[1].to_s
41
+ suffix=fixes[2].to_s
42
+ return map{|s| prefix + s.to_s + suffix}.ruby_join(infix)
43
+ else
44
+ raise "join(fixes[#{fixes.size}]"
45
+ end
46
+ end
47
+
48
+
49
+ # Return true if size > 0
50
+ #
51
+ # ==Examples
52
+ # [1,2,3].size? => true
53
+ # [].size? => false
54
+
55
+ def size?
56
+ return size>0
57
+ end
58
+
59
+
60
+ # Move the first item to the last by using Array#shift and Array#push
61
+ #
62
+ # ==Examples
63
+ # [1,2,3,4].rotate! => [2,3,4,1]
64
+ # ['a','b','c'].rotate! => ['b','c','a']
65
+ #
66
+ # Return self
67
+
68
+ def rotate!
69
+ push item=shift
70
+ self
71
+ end
72
+
73
+
74
+ # Return a random item from the array
75
+ #
76
+ # ==Examples
77
+ # [1,2,3,4].choice => 2
78
+ # [1,2,3,4].choice => 4
79
+ # [1,2,3,4].choice => 3
80
+ #
81
+ # Implemented in Ruby 1.9
82
+
83
+ def choice
84
+ self[Kernel.rand(size)]
85
+ end
86
+
87
+
88
+ # Return a new array filled with _count_ calls to choice
89
+ #
90
+ # ==Examples
91
+ # [1,2,3,4].choices(2) => [3,1]
92
+ # [1,2,3,4].choices(3) => [4,2,3]
93
+
94
+ def choices(count)
95
+ arr = Array.new
96
+ count.times { arr << self.choice }
97
+ return arr
98
+ end
99
+
100
+
101
+ # Return a hash of this array's items as keys
102
+ # mapped onto another array's items as values.
103
+ #
104
+ # ==Example
105
+ # foo=[:a,:b,:c]
106
+ # goo=[:x,:y,:z]
107
+ # foo.onto(goo) => {:a=>:x, :b=>:y, :c=>:z}
108
+ #
109
+ # This is identical to calling foo.zip(values).to_h
110
+
111
+ def onto(values)
112
+ zip(values).to_h
113
+ end
114
+
115
+
116
+ ##############################################################
117
+ #
118
+ # GROUPINGS
119
+ #
120
+ ##############################################################
121
+
122
+
123
+ # Return items in groups of _n_ items (aka slices)
124
+ #
125
+ # ==Examples
126
+ # [1,2,3,4,5,6,7,8].slices(2) => [[1,2],[3,4],[5,6],[7,8]]
127
+ # [1,2,3,4,5,6,7,8].slices(4) => [[1,2,3,4],[5,6,7,8]]
128
+ #
129
+ # If the slices don't divide evenly, then the last is smaller.
130
+ #
131
+ # ==Examples
132
+ # [1,2,3,4,5,6,7,8].slices(3) => [[1,2,3],[4,5,6],[7,8]]
133
+ # [1,2,3,4,5,6,7,8].slices(5) => [[1,2,3,4,5],[6,7,8]]
134
+
135
+ def slices(slice_length)
136
+ arr=[]
137
+ i=0
138
+ while i<length
139
+ arr.push self[i...(i+slice_length)]
140
+ i+=slice_length
141
+ end
142
+ return arr
143
+ end
144
+
145
+
146
+ # Divvy the array, like a pie, into _n_ number of slices.
147
+ #
148
+ # If the array divides evenly, then each slice has size/n items.
149
+ #
150
+ # Otherwise, divvy makes a best attempt by rounding up to give
151
+ # earlier slices one more item, which makes the last slice smaller:
152
+ #
153
+ # ==Examples
154
+ # [1,2,3,4,5].divvy(2) => [[1,2,3],[4,5]]
155
+ # [1,2,3,4,5,6,7].divvy(3) => [[1,2,3],[4,5,6],[7]]
156
+ #
157
+ # If the array size so small compared to _n_ that there is
158
+ # no mathematical way to _n_ slices, then divvy will return
159
+ # as many slices as it can.
160
+ #
161
+ # ==Examples
162
+ # [1,2,3,4,5,6].divvy(4) => [[1,2],[3,4],[5,6]]
163
+
164
+ def divvy(number_of_slices)
165
+ return slices((length.to_f/number_of_slices.to_f).ceil)
166
+ end
167
+
168
+
169
+ ##############################################################
170
+ #
171
+ # COMBINATIONS
172
+ #
173
+ ##############################################################
174
+
175
+
176
+ # Return the union of the array's items.
177
+ # In typical use, each item is an array.
178
+ #
179
+ # ==Example using Ruby Array pipe
180
+ # a=[1,2,3]
181
+ # b=[2,3,4]
182
+ # a | b => [1,2,3,4]
183
+ #
184
+ # ==Example using union method
185
+ # arr=[a,b]
186
+ # => [1,2,3,4]
187
+ #
188
+ # This is identical to
189
+
190
+ # ==Examples with proc
191
+ # arr.map(&:foo).union
192
+ # => foos that are in any of the array items
193
+
194
+ def union
195
+ inject{|inj,item| inj | item.to_a }
196
+ end
197
+
198
+
199
+ # Return the intersection of the array's items.
200
+ # In typical usage, each item is an array.
201
+ #
202
+ # ==Examples
203
+ # arr=[[1,2,3,4],[2,3,4,5],[3,4,5,6]]
204
+ # arr.intersect
205
+ # => [3,4]
206
+ #
207
+ # ==Examples with proc
208
+ # arr.map(&:foo).intersect
209
+ # => foos that are in all of the array items
210
+
211
+ def intersect
212
+ inject{|inj,item| inj & item.to_a }
213
+ end
214
+
215
+
216
+
217
+ ##############################################################
218
+ #
219
+ # LIST PROCESSING
220
+ #
221
+ ##############################################################
222
+
223
+ # Returns the rest of the items of self, after a shift.
224
+ #
225
+ # ==Example
226
+ # list=['a','b','c']
227
+ # list.shift => 'a'
228
+ # list.shifted => ['b','c']
229
+ #
230
+ # ==Example with length
231
+ # list.shifted(0) => ['a','b','c']
232
+ # list.shifted(1) => ['b','c']
233
+ # list.shifted(2) => ['c']
234
+ # list.shifted(3) => []
235
+ #
236
+ # Ruby programmers may prefer this alias wording:
237
+ # list.first => 'a'
238
+ # list.rest => ['b','c']
239
+ #
240
+ # LISP programmers may prefer this alias wording:
241
+ # list.car => 'a'
242
+ # list.cdr => ['b','c']
243
+ #
244
+
245
+ def shifted(number_of_items=1)
246
+ slice(n,self.length-number_of_items)
247
+ end
248
+
249
+ alias :car :first
250
+ alias :cdr :shifted
251
+ alias :rest :shifted
252
+
253
+
254
+ # Delete the first _number_of_items_ items. Returns the array, not the deleted items.
255
+ #
256
+ # ==Example
257
+ # list=['a','b','c']
258
+ # list.shifted!
259
+ # list => ['b','c']
260
+ #
261
+ # ==Example with length:
262
+ # list=['a','b','c']
263
+ # list.shifted!(2)
264
+ # list => ['c']
265
+ #
266
+ # If _n_ is greater than the array size, then return []
267
+
268
+ def shifted!(number_of_items=1)
269
+ slice!(0,number_of_items)
270
+ return self
271
+ end
272
+
273
+ alias :cdr! :shifted!
274
+ alias :rest! :shifted!
275
+
276
+
277
+ # Randomly arrange the array items.
278
+ #
279
+ # This implementation is optimized for speed, not for memory use.
280
+ # See http://codeidol.com/other/rubyckbk/Arrays/Shuffling-an-Array/
281
+ #
282
+ # This method definition is skipped if Array#shuffle! is already defined.
283
+ #
284
+ # ==Example
285
+ # list=
286
+ # list=['a','b','c']
287
+ # list.shuffle!
288
+ # list => ['c','a','b']
289
+
290
+ if !instance_methods.include?('shuffle!')
291
+ def shuffle!
292
+ each_index do |i|
293
+ j = rand(length-i) + i
294
+ self[j], self[i] = self[i], self[j]
295
+ end
296
+ end
297
+ end
298
+
299
+ # Return the array items in random order.
300
+ #
301
+ # This implementation is optimized for speed, not for memory use.
302
+ # See http://codeidol.com/other/rubyckbk/Arrays/Shuffling-an-Array/
303
+ #
304
+ # This method definition is skipped if Array#shuffle is already defined.
305
+ # For example, Ruby 1.8.7 Array#shuffle is already defined.
306
+ #
307
+ # ==Example
308
+ # list=
309
+ # list=['a','b','c']
310
+ # list.shuffle!
311
+ # list => ['c','a','b']
312
+
313
+ if !instance_methods.include?('shuffle') and instance_methods.include?('shuffle!')
314
+ def shuffle
315
+ dup.shuffle!
316
+ end
317
+ end
318
+
319
+
320
+ ##############################################################
321
+ #
322
+ # CASTS
323
+ #
324
+ ##############################################################
325
+
326
+ # Returns a CSV (Comma Separated Value) string of this array.
327
+ #
328
+ # ==Example of a one-dimensional array
329
+ #
330
+ # [1,2,3].to_csv => "1,2,3\n"
331
+ #
332
+ # ==Example of a multi-dimensional array
333
+ #
334
+ # [[1,2,3],[4,5,6]] => "1,2,3\n4,5,6\n"
335
+ #
336
+ # N.b. this method uses the multi-dimensional if the
337
+ # array's first item is also an array.
338
+
339
+ def to_csv(ops={})
340
+
341
+ generator = RUBY_VERSION >= "1.9" ? CSV : CSV::Writer
342
+
343
+ str=''
344
+ if size>0 and self[0].is_a?Array
345
+ generator.generate(str) do |csv|
346
+ self.each do |row|
347
+ csv << row
348
+ end
349
+ end
350
+ else
351
+ generator.generate(str) do |csv|
352
+ csv << self.map{|item| item.to_s}
353
+ end
354
+ end
355
+ return str
356
+ end
357
+
358
+
359
+ # Returns a TSV (Tab Separated Value) string
360
+ # representation of a multi-dimensional array.
361
+ #
362
+ # Each subarray becomes one 'line' in the output.
363
+
364
+ def to_tsv(ops={})
365
+ self.map{|row| row.join("\t")+"\n"}.join
366
+ end
367
+
368
+ alias to_tdf to_tsv
369
+
370
+ end