bjj 1.0.3

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