bj 0.0.1

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