buzzware-buzzcore 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,210 @@
1
+ require 'buzzcore/xml_utils'
2
+ require 'buzzcore/extend_base_classes'
3
+
4
+ class ConfigClass < Hash
5
+
6
+ attr_reader :default_values
7
+
8
+ def initialize(aDefaultValues,aNewValues=nil,&aBlock)
9
+ @default_values = aDefaultValues.clone
10
+ reset()
11
+ if aNewValues
12
+ block_given? ? read(aNewValues,&aBlock) : read(aNewValues)
13
+ end
14
+ end
15
+
16
+ # aBlock allows values to be filtered based on key,default and new values
17
+ def read(aSource,&aBlock)
18
+ default_values.each do |k,v|
19
+ done = false
20
+ if block_given? && ((newv = yield(k,v,aSource && aSource[k])) != nil)
21
+ self[k] = newv
22
+ done = true
23
+ end
24
+ copy_item(aSource,k) if !done && aSource && !aSource[k].nil?
25
+ end
26
+ self
27
+ end
28
+
29
+ # reset values back to defaults
30
+ def reset
31
+ self.clear
32
+ me = self
33
+ @default_values.each {|n,v| me[n] = v.is_a?(Class) ? nil : v}
34
+ end
35
+
36
+ def set_int(aKey,aValue)
37
+ case aValue
38
+ when String then self[aKey] = aValue.to_integer(self[aKey]);
39
+ when Fixnum then self[aKey] = aValue;
40
+ when Float then self[aKey] = aValue.to_i;
41
+ end
42
+ end
43
+
44
+ def set_float(aKey,aValue)
45
+ case aValue
46
+ when String then self[aKey] = aValue.to_float(self[aKey]);
47
+ when Fixnum then self[aKey] = aValue.to_f;
48
+ when Float then self[aKey] = aValue;
49
+ end
50
+ end
51
+
52
+ def set_boolean(aKey,aValue)
53
+ case aValue
54
+ when TrueClass,FalseClass then self[aKey] = aValue;
55
+ when String then self[aKey] = (['1','yes','y','true','on'].include?(aValue.downcase))
56
+ else
57
+ set_boolean(aKey,aValue.to_s)
58
+ end
59
+ end
60
+
61
+ def set_symbol(aKey,aValue)
62
+ case aValue
63
+ when String then self[aKey] = (aValue.to_sym rescue nil);
64
+ when Symbol then self[aKey] = aValue;
65
+ end
66
+ end
67
+
68
+ def copy_item(aHash,aKey)
69
+ d = default_values[aKey]
70
+ d_class = (d.is_a?(Class) ? d : d.class)
71
+ cname = d_class.name.to_sym
72
+ case cname
73
+ when :NilClass then ;
74
+ when :String then self[aKey] = aHash[aKey].to_s unless aHash[aKey].nil?
75
+ when :Float then set_float(aKey,aHash[aKey]);
76
+ when :Fixnum then set_int(aKey,aHash[aKey]);
77
+ when :TrueClass, :FalseClass then set_boolean(aKey,aHash[aKey]);
78
+ when :Symbol then self[aKey] = (aHash[aKey].to_sym rescue nil)
79
+ else
80
+ raise StandardError.new('unsupported type')
81
+ end
82
+ end
83
+
84
+ def copy_strings(aHash,*aKeys)
85
+ aKeys.each do |k|
86
+ self[k] = aHash[k].to_s unless aHash[k].nil?
87
+ end
88
+ end
89
+
90
+ def copy_ints(*aDb)
91
+ aHash = aDb.shift
92
+ aKeys = aDb
93
+ aKeys.each do |k|
94
+ set_int(k,aHash[k])
95
+ end
96
+ end
97
+
98
+ def copy_floats(aHash,*aKeys)
99
+ aKeys.each do |k|
100
+ set_float(k,aHash[k])
101
+ end
102
+ end
103
+
104
+ def copy_booleans(aHash,*aKeys)
105
+ aKeys.each do |k|
106
+ set_boolean(k,aHash[k])
107
+ end
108
+ end
109
+
110
+ def to_hash
111
+ {}.merge(self)
112
+ end
113
+
114
+ end
115
+
116
+ class ConfigXmlClass < ConfigClass
117
+ attr_accessor :xmlRoot
118
+ def initialize(aDefaultValues,aConfig)
119
+ return super(aDefaultValues,aConfig) unless aConfig.is_a?(REXML::Element)
120
+ @xmlRoot = aConfig.deep_clone
121
+ super(aDefaultValues,XmlUtils.read_simple_items(@xmlRoot,'SimpleItems').symbolize_keys)
122
+ end
123
+
124
+ def self.from_file(aDefaultValues,aFile)
125
+ xml = XmlUtils.get_file_root(aFile)
126
+ return ConfigXmlClass.new(aDefaultValues,xml)
127
+ end
128
+ end
129
+
130
+ # credentials files look like :
131
+ #<?xml version="1.0" encoding="UTF-8"?>
132
+ #<Credentials>
133
+ # <SimpleItems namespace="global">
134
+ # <Item name=""></Item>
135
+ # <Item name=""></Item>
136
+ # <Item name=""></Item>
137
+ # </SimpleItems>
138
+ # <SimpleItems namespace="yore_test">
139
+ # <Item name=""></Item>
140
+ # <Item name=""></Item>
141
+ # <Item name=""></Item>
142
+ # </SimpleItems>
143
+ #</Credentials>
144
+ #
145
+ # global .credentials.xml file
146
+ # local .credentials.xml file
147
+ # cred = Credentials.new() # optionally specify filename or path or hash. if nil then use Dir.pwd
148
+ #
149
+ # def initialize(aSource)
150
+ # # load global namespace from ~/.credentials.xml
151
+ # # load global namespace from local .credentials.xml
152
+ # # load given namespace from ~/.credentials.xml
153
+ # # load given namespace from local .credentials.xml
154
+ # # merge all top to bottom
155
+ class Credentials < Hash
156
+
157
+ CRED_FILENAME = ".credentials.xml"
158
+
159
+ def find_file_upwards(aFilename,aStartPath=nil)
160
+ aStartPath ||= Dir.pwd
161
+ return nil if aFilename.nil? || aFilename.empty?
162
+ arrPath = aStartPath.split(File::SEPARATOR)
163
+ while arrPath.length > 0
164
+ path = File.join(arrPath.join(File::SEPARATOR),aFilename)
165
+ return path if File.exists?(path)
166
+ arrPath.pop
167
+ end
168
+ return nil
169
+ end
170
+
171
+ def get_all_credentials(aXmlRoot)
172
+ return nil unless aXmlRoot
173
+ result = {}
174
+ REXML::XPath.each(aXmlRoot, '/Credentials/SimpleItems') do |si|
175
+ ns = si.attributes['Namespace']
176
+ values = XmlUtils.read_simple_items(si)
177
+ result[ns.to_sym] = values.symbolize_keys if ns && values
178
+ end
179
+ return result
180
+ end
181
+
182
+ #XmlUtils.read_simple_items(@xmlRoot,'/Yore/SimpleItems')
183
+ def get_user_credentials
184
+ return get_all_credentials(XmlUtils.get_file_root(File.join(HOME_PATH,CRED_FILENAME)))
185
+ end
186
+
187
+ def get_local_credentials(aSource=nil)
188
+ aSource ||= Dir.pwd
189
+ # assume source is a directory path, but other types could be supported later
190
+ return nil unless file=find_file_upwards(CRED_FILENAME,aSource)
191
+ return get_all_credentials(XmlUtils.get_file_root(file))
192
+ end
193
+
194
+ def initialize(aNamespace=nil,aSource=nil)
195
+ #HOME_PATH can be preset by tests eg. ::Credentials.const_set('HOME_PATH',@user_dir)
196
+ Credentials.const_set("HOME_PATH", ENV['HOME']) unless Credentials.const_defined? "HOME_PATH"
197
+ arrCredentials = []
198
+ user_credentials = get_user_credentials()
199
+ local_credentials = get_local_credentials(aSource)
200
+ arrCredentials << user_credentials[:global] if user_credentials
201
+ arrCredentials << local_credentials[:global] if local_credentials
202
+ arrCredentials << user_credentials[aNamespace.to_sym] if aNamespace && user_credentials
203
+ arrCredentials << local_credentials[aNamespace.to_sym] if aNamespace && local_credentials
204
+ arrCredentials.compact!
205
+ arrCredentials.each do |c|
206
+ self.merge!(c)
207
+ end
208
+ end
209
+ end
210
+
@@ -0,0 +1,86 @@
1
+ require 'buzzcore/shell_extras'
2
+
3
+ module DatabaseUtils
4
+ def self.execute_sql_file(filename,aUser=nil,aPassword=nil)
5
+ conf = ActiveRecord::Base.configurations[RAILS_ENV]
6
+ pw = aPassword || conf['password'].to_s || ''
7
+ user = aUser || conf['username'].to_s || ''
8
+ cmd_line = "mysql -h #{conf['host']} -D #{conf['database']} #{user.empty? ? '' : '-u '+user} #{pw.empty? ? '' : '-p'+pw} <#{filename}"
9
+ if !system(cmd_line)
10
+ raise Exception, "Error executing "+cmd_line
11
+ end
12
+ end
13
+
14
+ ## http://www.cyberciti.biz/faq/how-do-i-empty-mysql-database/
15
+ #
16
+ #
17
+ ## drop all tables :
18
+ ## mysqldump -uusername -ppassword -hhost \
19
+ ##--add-drop-table --no-data database | grep ^DROP | \
20
+ ##mysql -uusername -ppassword -hhost database
21
+ #
22
+
23
+ def self.database_exists(aDbDetails,aDatabase=nil)
24
+ aDbDetails[:database] = aDatabase if aDatabase
25
+ return false if !aDbDetails[:database]
26
+ response = POpen4::shell("mysql -u #{aDbDetails[:username]} -p#{aDbDetails[:password]} -e 'use #{aDbDetails[:database]}'") do |r|
27
+ if r[:stderr] && r[:stderr].index("ERROR 1049 ")==0 # Unknown database
28
+ r[:exitcode] = 0
29
+ return false
30
+ end
31
+ end
32
+ return (response && response[:exitcode]==0)
33
+ end
34
+
35
+ def self.clear_database(aDbDetails)
36
+ response = POpen4::shell("mysqldump -u #{aDbDetails[:username]} -p#{aDbDetails[:password]} --add-drop-table --no-data #{aDbDetails[:database]} | grep ^DROP | mysql -u #{aDbDetails[:username]} -p#{aDbDetails[:password]} #{aDbDetails[:database]}")
37
+ end
38
+
39
+ def self.create_database(aDbDetails,aDatabase=nil)
40
+ aDbDetails[:database] = aDatabase if aDatabase
41
+ return false if !aDbDetails[:database]
42
+ response = POpen4::shell("mysqladmin -u #{aDbDetails[:username]} -p#{aDbDetails[:password]} create #{aDbDetails[:database]}")
43
+ end
44
+
45
+ def self.ensure_empty_database(aDbDetails,aDatabase=nil)
46
+ aDbDetails[:database] = aDatabase if aDatabase
47
+ if database_exists(aDbDetails)
48
+ clear_database(aDbDetails)
49
+ else
50
+ create_database(aDbDetails)
51
+ end
52
+ end
53
+
54
+ def self.load_database(aDbDetails,aSqlFile)
55
+ ensure_empty_database(aDbDetails)
56
+ response = POpen4::shell("mysql -u #{aDbDetails[:username]} -p#{aDbDetails[:password]} #{aDbDetails[:database]} < #{aSqlFile}")
57
+ end
58
+
59
+ def self.save_database(aDbDetails,aSqlFile)
60
+ response = POpen4::shell("mysqldump --user=#{aDbDetails[:username]} --password=#{aDbDetails[:password]} --skip-extended-insert #{aDbDetails[:database]} > #{aSqlFile}")
61
+ end
62
+
63
+ #
64
+ ## eg. rake metas:spree:data:load from=/tmp/spree_data.tgz to=mysql:fresco_server_d:root:password
65
+ #desc 'load spree data from a file'
66
+ #task :load do
67
+ # from = ENV['from']
68
+ # to=ENV['to']
69
+ # db_server,db,user,password = to.split(':')
70
+ # tmpdir = make_temp_dir('metas')
71
+ # cmd = "tar -xvzf #{from} -C #{tmpdir}"
72
+ # puts CapUtilsClass.shell(cmd)
73
+ #
74
+ # ensure_empty_database(db_server,db,user,password)
75
+ #
76
+ # puts CapUtilsClass.shell("mysql -u #{user} -p#{password} #{db} < #{File.join(tmpdir,'db/dumps/db.sql')}")
77
+ # FileUtils.mkdir_p('public/assets')
78
+ # puts CapUtilsClass.shell("cp -rf #{File.join(tmpdir,'public/assets/products')} public/assets/products")
79
+ #end
80
+
81
+
82
+
83
+
84
+ end
85
+
86
+
@@ -0,0 +1,50 @@
1
+ module Kernel
2
+ # simple (sequential) enumerated values
3
+ # usage :
4
+ #
5
+ # module Constants
6
+ # module Gradient
7
+ # enum :B, :A, :C
8
+ # end
9
+ # end
10
+ #
11
+ # then :
12
+ #
13
+ # puts Constants::Gradient::B -> 0
14
+ # puts Constants::Gradient::C -> 2
15
+ # puts Constants::Gradient::MINVALUE -> 0
16
+ # puts Constants::Gradient::MAXVALUE -> 2
17
+ # puts Constants::Gradient::NAMES -> [:B, :A, :C]
18
+ # puts Constants::Gradient[0] -> :B
19
+ # puts Constants::Gradient[1] -> :A
20
+ # puts Constants::Gradient[2] -> :C
21
+
22
+ def enum(*syms)
23
+ syms.each_index { |i|
24
+ const_set(syms[i], i)
25
+ }
26
+ const_set(:NAMES, syms || [])
27
+ const_set(:MINVALUE, syms==nil ? nil : 0)
28
+ const_set(:MAXVALUE, syms==nil ? nil : syms.length-1)
29
+ const_set(:VALUECOUNT, syms==nil ? nil : syms.length)
30
+ const_set(:ALL, syms==nil ? [] : (0..syms.length-1).to_a)
31
+ const_set(:HUMAN_NAMES, syms.map{|n| n.to_s.humanize} || [])
32
+
33
+ # this returns the enum name given the value
34
+ def self.[]( idx )
35
+ (idx.is_a? Integer) ? const_get(:NAMES)[idx] : nil
36
+ end
37
+
38
+ def self.valid?(idx)
39
+ (idx.is_a? Integer) && (idx >= 0) && (idx <= const_get(:MAXVALUE))
40
+ end
41
+
42
+ def self.parse(name,default=nil)
43
+ return default if name.nil? || name.empty?
44
+ return default if not name = name.to_sym
45
+ result = const_get(:NAMES).index(name)
46
+ return result==nil ? default : result
47
+ end
48
+ end
49
+ end
50
+
@@ -0,0 +1,320 @@
1
+ String.class_eval do
2
+ def pad_left(value)
3
+ increase = value-self.length
4
+ return self if increase==0
5
+ if increase > 0
6
+ return self + ' '*increase
7
+ else
8
+ return self[0,value]
9
+ end
10
+ end
11
+
12
+ def pad_right(value)
13
+ increase = value-self.length
14
+ return self if increase==0
15
+ if increase > 0
16
+ return ' '*increase + self
17
+ else
18
+ return self[0,value]
19
+ end
20
+ end
21
+
22
+ # Like chomp! but operates on the leading characters instead.
23
+ # The aString parameter would not normally be used.
24
+ def bite!(aValue=$/,aString=self)
25
+ if aString[0,aValue.length] == aValue
26
+ aString[0,aValue.length] = ''
27
+ return aString
28
+ else
29
+ return aString
30
+ end
31
+ end
32
+
33
+ def bite(aValue=$/)
34
+ bite!(aValue,self.clone)
35
+ end
36
+
37
+ def begins_with?(aString)
38
+ self[0,aString.length]==aString
39
+ end
40
+
41
+ def ends_with?(aString)
42
+ self[-aString.length,aString.length]==aString
43
+ end
44
+
45
+ # for future methods
46
+ # def centre_bar(aChar = '-', indent = 6)
47
+ # (' '*indent) + aChar*(@width-(indent*2)) + (' '*indent)
48
+ # end
49
+ # def replace_string(aString,aCol,aSubString)
50
+ # return aString if aSubString==nil || aSubString==''
51
+ #
52
+ # aSubString = aSubString.to_s
53
+ # start_col = aCol < 0 ? 0 : aCol
54
+ # end_col = aCol+aSubString.length-1
55
+ # end_col = @width-1 if end_col >= @width
56
+ # source_len = end_col-start_col+1
57
+ # return aString if source_len <= 0 || end_col < 0 || start_col >= @width
58
+ # aString += ' '*((end_col+1) - aString.length) if aString.length < end_col+1
59
+ # aString[start_col,source_len] = aSubString[start_col-aCol,end_col-start_col+1]
60
+ # return aString
61
+ # end
62
+
63
+ def to_integer(aDefault=nil)
64
+ t = self.strip
65
+ return aDefault if t.empty? || !t.index(/^-{0,1}[0-9]+$/)
66
+ return t.to_i
67
+ end
68
+
69
+ def is_i?
70
+ self.to_integer(false) and true
71
+ end
72
+
73
+ def to_float(aDefault=nil)
74
+ t = self.strip
75
+ return aDefault if !t =~ /(\+|-)?([0-9]+\.?[0-9]*|\.[0-9]+)([eE](\+|-)?[0-9]+)?/
76
+ return t.to_f
77
+ end
78
+
79
+ def is_f?
80
+ self.to_float(false) and true
81
+ end
82
+
83
+ end
84
+
85
+
86
+ Time.class_eval do
87
+
88
+ if !respond_to?(:change) # no activesupport loaded
89
+ def change(options)
90
+ ::Time.send(
91
+ self.utc? ? :utc : :local,
92
+ options[:year] || self.year,
93
+ options[:month] || self.month,
94
+ options[:day] || self.day,
95
+ options[:hour] || self.hour,
96
+ options[:min] || (options[:hour] ? 0 : self.min),
97
+ options[:sec] || ((options[:hour] || options[:min]) ? 0 : self.sec),
98
+ options[:usec] || ((options[:hour] || options[:min] || options[:sec]) ? 0 : self.usec)
99
+ )
100
+ end
101
+
102
+ def seconds_since_midnight
103
+ self.to_i - self.change(:hour => 0).to_i + (self.usec/1.0e+6)
104
+ end
105
+
106
+ def beginning_of_day
107
+ (self - self.seconds_since_midnight).change(:usec => 0)
108
+ end
109
+
110
+ alias :midnight :beginning_of_day
111
+ alias :at_midnight :beginning_of_day
112
+ alias :at_beginning_of_day :beginning_of_day
113
+
114
+ end
115
+
116
+ # offset of local machine from UTC, in seconds eg +9.hours
117
+ def self.local_offset
118
+ local(2000).utc_offset
119
+ end
120
+
121
+ def date
122
+ self.at_beginning_of_day
123
+ end
124
+
125
+ # index number of this day, from Time.at(0) + utc_offset
126
+ def day_number
127
+ (self.to_i+self.utc_offset) / 86400
128
+ end
129
+
130
+ # index number of this utc day
131
+ def day_number_utc
132
+ self.to_i / 86400
133
+ end
134
+
135
+ # the last microsecond of the day
136
+ def day_end
137
+ self.at_beginning_of_day + 86399.999999
138
+ end
139
+
140
+ def date_numeric
141
+ self.strftime('%Y%m%d')
142
+ end
143
+
144
+ # create a new Time from eg. "20081231"
145
+ def self.from_date_numeric(aString)
146
+ return nil unless aString
147
+ local(aString[0,4].to_i,aString[4,2].to_i,aString[6,2].to_i)
148
+ end
149
+
150
+ def time_numeric
151
+ self.strftime('%H%M%S')
152
+ end
153
+
154
+ def datetime_numeric
155
+ self.strftime('%Y%m%d-%H%M%S')
156
+ end
157
+
158
+ def to_sql
159
+ self.strftime('%Y-%m-%d %H:%M:%S')
160
+ end
161
+
162
+ def to_w3c
163
+ utc.strftime("%Y-%m-%dT%H:%M:%S+00:00")
164
+ end
165
+ end
166
+
167
+ module HashUtils
168
+ def filter_include!(aKeys,aHash=nil)
169
+ aHash ||= self
170
+
171
+ if aKeys.is_a? Regexp
172
+ return aHash.delete_if {|k,v| not k =~ aKeys }
173
+ else
174
+ aKeys = [aKeys] unless aKeys.is_a? Array
175
+ return aHash.clear if aKeys.empty?
176
+ return aHash.delete_if {|key, value| !((aKeys.include?(key)) || (key.is_a?(Symbol) and aKeys.include?(key.to_s)) || (key.is_a?(String) and aKeys.include?(key.to_sym)))}
177
+ return aHash # last resort
178
+ end
179
+ end
180
+
181
+ def filter_include(aKeys,aHash=nil)
182
+ aHash ||= self
183
+ filter_include!(aKeys,aHash.clone)
184
+ end
185
+
186
+ def filter_exclude!(aKeys,aHash=nil)
187
+ aHash ||= self
188
+
189
+ if aKeys.is_a? Regexp
190
+ return aHash.delete_if {|k,v| k =~ aKeys }
191
+ else
192
+ aKeys = [aKeys] unless aKeys.is_a? Array
193
+ return aHash if aKeys.empty?
194
+ return aHash.delete_if {|key, value| ((aKeys.include?(key)) || (key.is_a?(Symbol) and aKeys.include?(key.to_s)) || (key.is_a?(String) and aKeys.include?(key.to_sym)))}
195
+ end
196
+ end
197
+
198
+ def filter_exclude(aKeys,aHash=nil)
199
+ aHash ||= self
200
+ filter_exclude!(aKeys,aHash.clone)
201
+ end
202
+
203
+ def has_values_for?(aKeys,aHash=nil)
204
+ aHash ||= self
205
+ # check all keys exist in aHash and their values are not nil
206
+ aKeys.all? { |k,v| aHash[k] }
207
+ end
208
+
209
+ # give a block to execute without the given key in this hash
210
+ # It will be replaced after the block (guaranteed by ensure)
211
+ # eg.
212
+ # hash.without_key(:blah) do |aHash|
213
+ # puts aHash.inspect
214
+ # end
215
+ def without_key(aKey)
216
+ temp = nil
217
+ h = self
218
+ begin
219
+ if h.include?(aKey)
220
+ temp = [aKey,h.delete(aKey)]
221
+ end
222
+ result = yield(h)
223
+ ensure
224
+ h[temp[0]] = temp[1] if temp
225
+ end
226
+ return result
227
+ end
228
+
229
+ def symbolize_keys
230
+ result = {}
231
+ self.each { |k,v| k.is_a?(String) ? result[k.to_sym] = v : result[k] = v }
232
+ return result
233
+ end
234
+
235
+ end
236
+
237
+ Hash.class_eval do
238
+ include HashUtils
239
+ end
240
+
241
+ if defined? HashWithIndifferentAccess
242
+ HashWithIndifferentAccess.class_eval do
243
+ include HashUtils
244
+ end
245
+ end
246
+
247
+ module ArrayUtils
248
+ def filter_include!(aValues,aArray=nil)
249
+ aArray ||= self
250
+ if aValues.is_a? Array
251
+ return aArray if aValues.empty?
252
+ return aArray.delete_if {|v| not aValues.include? v }
253
+ elsif aValues.is_a? Regexp
254
+ return aArray.delete_if {|v| not v =~ aValues }
255
+ else
256
+ return filter_include!([aValues],aArray)
257
+ end
258
+ end
259
+
260
+ def filter_include(aValues,aArray=nil)
261
+ aArray ||= self
262
+ filter_include!(aValues,aArray.clone)
263
+ end
264
+
265
+ def filter_exclude!(aValues,aArray=nil)
266
+ aArray ||= self
267
+ if aValues.is_a? Array
268
+ return aArray if aValues.empty?
269
+ return aArray.delete_if {|v| aValues.include? v }
270
+ elsif aValues.is_a? Regexp
271
+ return aArray.delete_if {|v| v =~ aValues }
272
+ else
273
+ return filter_exclude!([aValues],aArray)
274
+ end
275
+ end
276
+
277
+ def filter_exclude(aValues,aArray=nil)
278
+ aArray ||= self
279
+ filter_exclude!(aValues,aArray.clone)
280
+ end
281
+ end
282
+
283
+ Array.class_eval do
284
+ include ArrayUtils
285
+
286
+ # fixes a memory leak in shift in Ruby 1.8 - should be fixed in 1.9
287
+ # see http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/216055
288
+ def shift()
289
+ delete_at(0)
290
+ end
291
+
292
+ end
293
+
294
+ Kernel.class_eval do
295
+ def is_windows?
296
+ RUBY_PLATFORM =~ /(win|w)32$/ ? true : false
297
+ end
298
+ end
299
+
300
+ if defined? ActiveRecord
301
+ ActiveRecord::Base.class_eval do
302
+
303
+ def self.find_any_id(aId)
304
+ with_exclusive_scope { find(:first, {:conditions => {:id => aId}}) }
305
+ end
306
+
307
+ def self.find_any_all(aOptions={})
308
+ with_exclusive_scope { find(:all, aOptions) }
309
+ end
310
+
311
+ def self.find_ids(aIds)
312
+ find(:all, {:conditions=> ["id in (?)",aIds.join(',')]})
313
+ end
314
+
315
+ def self.find_any_ids(aIds)
316
+ with_exclusive_scope { find(:all, {:conditions=> ["id in (?)",aIds.join(',')]}) }
317
+ end
318
+
319
+ end
320
+ end