bj 0.0.1

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.
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