webget_ruby_ramp 1.7.2
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/lib/webget_ruby_ramp.rb +250 -0
- data/lib/webget_ruby_ramp/active_record.rb +119 -0
- data/lib/webget_ruby_ramp/active_record/connection_adapters/abstract/schema_statements.rb +24 -0
- data/lib/webget_ruby_ramp/active_record/save_extensions.rb +35 -0
- data/lib/webget_ruby_ramp/array.rb +370 -0
- data/lib/webget_ruby_ramp/csv.rb +53 -0
- data/lib/webget_ruby_ramp/date.rb +90 -0
- data/lib/webget_ruby_ramp/enumerable.rb +385 -0
- data/lib/webget_ruby_ramp/file.rb +15 -0
- data/lib/webget_ruby_ramp/hash.rb +223 -0
- data/lib/webget_ruby_ramp/integer.rb +22 -0
- data/lib/webget_ruby_ramp/io.rb +65 -0
- data/lib/webget_ruby_ramp/kernel.rb +36 -0
- data/lib/webget_ruby_ramp/math.rb +20 -0
- data/lib/webget_ruby_ramp/nil.rb +17 -0
- data/lib/webget_ruby_ramp/numeric.rb +98 -0
- data/lib/webget_ruby_ramp/object.rb +20 -0
- data/lib/webget_ruby_ramp/process.rb +153 -0
- data/lib/webget_ruby_ramp/string.rb +221 -0
- data/lib/webget_ruby_ramp/symbol.rb +11 -0
- data/lib/webget_ruby_ramp/time.rb +11 -0
- data/lib/webget_ruby_ramp/xml.rb +193 -0
- data/lib/webget_ruby_ramp/yaml.rb +34 -0
- data/test/webget_ruby_ramp/active_record/connection_adapters/abstract/schema_statements_test.rb +9 -0
- data/test/webget_ruby_ramp/active_record/save_extensions_test.rb +7 -0
- data/test/webget_ruby_ramp/active_record_test.rb +64 -0
- data/test/webget_ruby_ramp/array_test.rb +171 -0
- data/test/webget_ruby_ramp/csv_test.rb +18 -0
- data/test/webget_ruby_ramp/date_test.rb +60 -0
- data/test/webget_ruby_ramp/enumerable_test.rb +275 -0
- data/test/webget_ruby_ramp/file_test.rb +15 -0
- data/test/webget_ruby_ramp/hash_test.rb +105 -0
- data/test/webget_ruby_ramp/integer_test.rb +19 -0
- data/test/webget_ruby_ramp/io_test.rb +31 -0
- data/test/webget_ruby_ramp/io_test.txt +1 -0
- data/test/webget_ruby_ramp/kernel_test.rb +15 -0
- data/test/webget_ruby_ramp/math_test.rb +17 -0
- data/test/webget_ruby_ramp/nil_test.rb +15 -0
- data/test/webget_ruby_ramp/numeric_test.rb +28 -0
- data/test/webget_ruby_ramp/object_test.rb +12 -0
- data/test/webget_ruby_ramp/process_test.rb +24 -0
- data/test/webget_ruby_ramp/string_test.rb +125 -0
- data/test/webget_ruby_ramp/symbol_test.rb +26 -0
- data/test/webget_ruby_ramp/time_test.rb +12 -0
- data/test/webget_ruby_ramp/xml_test.rb +93 -0
- data/test/webget_ruby_ramp/xml_test_1.xml +5 -0
- data/test/webget_ruby_ramp/xml_test_2.xml +5 -0
- data/test/webget_ruby_ramp/xml_test_msword_clean.html +1 -0
- data/test/webget_ruby_ramp/xml_test_msword_dirty.html +148 -0
- data/test/webget_ruby_ramp/yaml_test.rb +32 -0
- data/test/webget_ruby_ramp/yaml_test_1.yml +38 -0
- data/test/webget_ruby_ramp/yaml_test_2.yml +38 -0
- metadata +128 -0
- 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
|