bjj 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,86 @@
1
+ class Hash
2
+ begin
3
+ method "to_options"
4
+ rescue
5
+ def to_options
6
+ inject(Hash.new){|h, kv| h.update kv.first.to_s.to_sym => kv.last}
7
+ end
8
+ def to_options!
9
+ replace to_options
10
+ end
11
+ end
12
+
13
+ begin
14
+ method "to_string_options"
15
+ rescue
16
+ def to_string_options
17
+ inject(Hash.new){|h, kv| h.update kv.first.to_s => kv.last}
18
+ end
19
+ def to_string_options!
20
+ replace to_string_options
21
+ end
22
+ end
23
+
24
+ begin
25
+ method "reverse_merge"
26
+ rescue
27
+ def reverse_merge other
28
+ other.merge self
29
+ end
30
+ def reverse_merge! other
31
+ replace reverse_merge(other)
32
+ end
33
+ end
34
+
35
+ begin
36
+ method "slice"
37
+ rescue
38
+ def slice(*keys)
39
+ allowed = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
40
+ reject { |key,| !allowed.include?(key) }
41
+ end
42
+ end
43
+
44
+ begin
45
+ method "slice!"
46
+ rescue
47
+ def slice!(*keys)
48
+ replace(slice(*keys))
49
+ end
50
+ end
51
+ end
52
+
53
+ class Object
54
+ begin
55
+ method "returning"
56
+ rescue
57
+ def returning value, &block
58
+ block.call value
59
+ value
60
+ end
61
+ end
62
+ end
63
+
64
+ class Object
65
+ def singleton_class &block
66
+ @singleton_class ||=
67
+ class << self
68
+ self
69
+ end
70
+ block ? @singleton_class.module_eval(&block) : @singleton_class
71
+ end
72
+ end
73
+
74
+ class String
75
+ begin
76
+ method 'underscore'
77
+ rescue
78
+ def underscore
79
+ gsub(/::/, '/').
80
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
81
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
82
+ tr("-", "_").
83
+ downcase
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,384 @@
1
+ class Bj
2
+ #
3
+ # table base class
4
+ #
5
+ class Table < ActiveRecord::Base
6
+ module ClassMethods
7
+ attribute("list"){ Array.new }
8
+ attribute("migration"){}
9
+
10
+ def migration_code classname = "BjMigration"
11
+ <<-code
12
+ class #{ classname } < ActiveRecord::Migration
13
+ def self.up
14
+ Bj::Table.each{|table| table.up}
15
+ end
16
+ def self.down
17
+ Bj::Table.reverse_each{|table| table.down}
18
+ end
19
+ end
20
+ code
21
+ end
22
+
23
+ def up
24
+ migration_class.up
25
+ end
26
+
27
+ def down
28
+ migration_class.down
29
+ end
30
+
31
+ def migration_class
32
+ table = self
33
+ @migration_class ||=
34
+ Class.new(ActiveRecord::Migration) do
35
+ sc =
36
+ class << self
37
+ self
38
+ end
39
+ sc.module_eval{ attribute :table => table }
40
+ sc.module_eval &table.migration
41
+ end
42
+ end
43
+
44
+ def content_column_names
45
+ @content_column_names = content_columns.map{|column| column.name}
46
+ end
47
+
48
+ def create_hash_for options
49
+ options.to_options!
50
+ hash = {}
51
+ content_column_names.each do |key|
52
+ key = key.to_s.to_sym
53
+ hash[key] = options[key]
54
+ end
55
+ hash
56
+ end
57
+
58
+ def each *a, &b
59
+ list.each *a, &b
60
+ end
61
+
62
+ def reverse_each *a, &b
63
+ list.reverse.each *a, &b
64
+ end
65
+ end
66
+ send :extend, ClassMethods
67
+
68
+ module InstanceMethods
69
+ def to_hash
70
+ oh = OrderedHash.new
71
+ self.class.content_column_names.each{|c| oh[c] = self[c]}
72
+ oh
73
+ end
74
+ end
75
+ send :include, InstanceMethods
76
+
77
+ module RecursivelyInherited
78
+ def inherited other
79
+ super
80
+ ensure
81
+ (Table.list << other).uniq!
82
+ basename = other.name.split(%r/::/).last.underscore
83
+ Table.singleton_class{ attribute basename => other }
84
+ other.send :extend, RecursivelyInherited
85
+ end
86
+ end
87
+ send :extend, RecursivelyInherited
88
+
89
+ #
90
+ # table classes
91
+ #
92
+ class Job < Table
93
+ set_table_name "bj_job"
94
+ set_primary_key "#{ table_name }_id"
95
+
96
+ migration {
97
+ define_method :up do
98
+ create_table table.table_name, :primary_key => table.primary_key, :force => true do |t|
99
+ t.column "command" , :text
100
+
101
+ t.column "state" , :text
102
+ t.column "priority" , :integer
103
+ t.column "tag" , :text
104
+ t.column "is_restartable" , :integer
105
+
106
+ t.column "submitter" , :text
107
+ t.column "runner" , :text
108
+ t.column "pid" , :integer
109
+
110
+ t.column "submitted_at" , :datetime
111
+ t.column "started_at" , :datetime
112
+ t.column "finished_at" , :datetime
113
+
114
+ t.column "env" , :text
115
+ t.column "stdin" , :text
116
+ t.column "stdout" , :text
117
+ t.column "stderr" , :text
118
+ t.column "exit_status" , :integer
119
+ end
120
+ end
121
+
122
+ define_method :down do
123
+ drop_table table.table_name
124
+ end
125
+ }
126
+
127
+ module ClassMethods
128
+ def submit jobs, options = {}, &block
129
+ jobs = Joblist.for jobs, options
130
+ returned = []
131
+ transaction do
132
+ jobs.each do |job|
133
+ job = create_hash_for(job.reverse_merge(submit_defaults))
134
+ job = create! job
135
+ returned << (block ? block.call(job) : job)
136
+ end
137
+ end
138
+ returned
139
+ end
140
+
141
+ def submit_defaults
142
+ {
143
+ :state => "pending",
144
+ :priority => 0,
145
+ :tag => "",
146
+ :is_restartable => true,
147
+ :submitter => Bj.hostname,
148
+ :submitted_at => Time.now,
149
+ }
150
+ end
151
+ end
152
+ send :extend, ClassMethods
153
+
154
+ module InstanceMethods
155
+ def title
156
+ "job[#{ id }](#{ command })"
157
+ end
158
+ def finished
159
+ reload
160
+ exit_status
161
+ end
162
+ alias_method "finished?", "finished"
163
+ end
164
+ send :include, InstanceMethods
165
+ end
166
+
167
+ class JobArchive < Job
168
+ set_table_name "bj_job_archive"
169
+ set_primary_key "#{ table_name }_id"
170
+
171
+ migration {
172
+ define_method(:up) do
173
+ create_table table.table_name, :primary_key => table.primary_key, :force => true do |t|
174
+ t.column "command" , :text
175
+
176
+ t.column "state" , :text
177
+ t.column "priority" , :integer
178
+ t.column "tag" , :text
179
+ t.column "is_restartable" , :integer
180
+
181
+ t.column "submitter" , :text
182
+ t.column "runner" , :text
183
+ t.column "pid" , :integer
184
+
185
+ t.column "submitted_at" , :datetime
186
+ t.column "started_at" , :datetime
187
+ t.column "finished_at" , :datetime
188
+ t.column "archived_at" , :datetime
189
+
190
+ t.column "env" , :text
191
+ t.column "stdin" , :text
192
+ t.column "stdout" , :text
193
+ t.column "stderr" , :text
194
+ t.column "exit_status" , :integer
195
+ end
196
+ end
197
+
198
+ define_method(:down) do
199
+ drop_table table.table_name
200
+ end
201
+ }
202
+ end
203
+
204
+ # TODO - initialize with a set of global defaults and fallback to those on perhaps '* * key'
205
+ class Config < Table
206
+ set_table_name "bj_config"
207
+ set_primary_key "#{ table_name }_id"
208
+
209
+ migration {
210
+ define_method(:up) do
211
+ create_table table.table_name, :primary_key => table.primary_key, :force => true do |t|
212
+ t.column "hostname" , :text
213
+ t.column "key" , :text
214
+ t.column "value" , :text
215
+ t.column "cast" , :text
216
+ end
217
+
218
+ begin
219
+ add_index table.table_name, %w[ hostname key ], :unique => true
220
+ rescue Exception
221
+ STDERR.puts "WARNING: your database does not support unique indexes on text fields!?"
222
+ end
223
+ end
224
+
225
+ define_method(:down) do
226
+ begin
227
+ remove_index table.table_name, :column => %w[ hostname key ]
228
+ rescue Exception
229
+ end
230
+ drop_table table.table_name
231
+ end
232
+ }
233
+
234
+ module ClassMethods
235
+ def [] key
236
+ get key
237
+ end
238
+
239
+ def get key, options = {}
240
+ transaction do
241
+ options.to_options!
242
+ hostname = options[:hostname] || Bj.hostname
243
+ record = find :first, :conditions => conditions(:key => key, :hostname => hostname)
244
+ record ? record.value : default_for(key)
245
+ end
246
+ end
247
+
248
+ def conditions options = {}
249
+ options.to_options!
250
+ options.reverse_merge!(
251
+ :hostname => Bj.hostname
252
+ )
253
+ options
254
+ end
255
+
256
+ def default_for key
257
+ record = find :first, :conditions => conditions(:key => key, :hostname => '*')
258
+ record ? record.value : nil
259
+ end
260
+
261
+ def []= key, value
262
+ set key, value
263
+ end
264
+
265
+ def set key, value, options = {}
266
+ transaction do
267
+ options.to_options!
268
+ hostname = options[:hostname] || Bj.hostname
269
+ record = find :first, :conditions => conditions(:key => key, :hostname => hostname), :lock => true
270
+ cast = options[:cast] || cast_for(value)
271
+ key = key.to_s
272
+ value = value.to_s
273
+ if record
274
+ record["value"] = value
275
+ record["cast"] = cast
276
+ record.save!
277
+ else
278
+ create! :hostname => hostname, :key => key, :value => value, :cast => cast
279
+ end
280
+ value
281
+ end
282
+ end
283
+
284
+ def delete key
285
+ transaction do
286
+ record = find :first, :conditions => conditions(:key => key), :lock => true
287
+ if record
288
+ record.destroy
289
+ record
290
+ else
291
+ nil
292
+ end
293
+ end
294
+ end
295
+
296
+ def has_key? key
297
+ record = find :first, :conditions => conditions(:key => key)
298
+ record ? record : false
299
+ end
300
+ alias_method "has_key", "has_key?"
301
+
302
+ def keys
303
+ find(:all, :conditions => conditions).map(&:key)
304
+ end
305
+
306
+ def values
307
+ find(:all, :conditions => conditions).map(&:value)
308
+ end
309
+
310
+ def for options = {}
311
+ oh = OrderedHash.new
312
+ find(:all, :conditions => conditions(options)).each do |record|
313
+ oh[record.key] = record.value
314
+ end
315
+ oh
316
+ end
317
+
318
+ def cast_for value
319
+ case value
320
+ when TrueClass, FalseClass
321
+ 'to_bool'
322
+ when NilClass
323
+ 'to_nil'
324
+ when Fixnum, Bignum
325
+ 'to_i'
326
+ when Float
327
+ 'to_f'
328
+ when Time
329
+ 'to_time'
330
+ when Symbol
331
+ 'to_sym'
332
+ else
333
+ case value.to_s
334
+ when %r/^\d+$/
335
+ 'to_i'
336
+ when %r/^\d+\.\d+$/
337
+ 'to_f'
338
+ when %r/^nil$|^$/
339
+ 'to_nil'
340
+ when %r/^true|false$/
341
+ 'to_bool'
342
+ else
343
+ 'to_s'
344
+ end
345
+ end
346
+ end
347
+
348
+ def casts
349
+ @casts ||= {
350
+ 'to_bool' => lambda do |value|
351
+ value.to_s =~ %r/^true$/i ? true : false
352
+ end,
353
+ 'to_i' => lambda do |value|
354
+ Integer value.to_s.gsub(%r/^(-)?0*/,'\1')
355
+ end,
356
+ 'to_f' => lambda do |value|
357
+ Float value.to_s.gsub(%r/^0*/,'')
358
+ end,
359
+ 'to_time' => lambda do |value|
360
+ Time.parse(value.to_s)
361
+ end,
362
+ 'to_sym' => lambda do |value|
363
+ value.to_s.to_sym
364
+ end,
365
+ 'to_nil' => lambda do |value|
366
+ value.to_s =~ %r/^nil$|^$/i ? nil : value.to_s
367
+ end,
368
+ 'to_s' => lambda do |value|
369
+ value.to_s
370
+ end,
371
+ }
372
+ end
373
+ end
374
+ send :extend, ClassMethods
375
+
376
+ module InstanceMethods
377
+ def value
378
+ self.class.casts[cast][self["value"]]
379
+ end
380
+ end
381
+ send :include, InstanceMethods
382
+ end
383
+ end
384
+ end