rq-ruby1.8 3.4.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +22 -0
- data/Gemfile.lock +22 -0
- data/INSTALL +166 -0
- data/LICENSE +10 -0
- data/Makefile +6 -0
- data/README +1183 -0
- data/Rakefile +37 -0
- data/TODO +24 -0
- data/TUTORIAL +230 -0
- data/VERSION +1 -0
- data/bin/rq +902 -0
- data/bin/rqmailer +865 -0
- data/example/a.rb +7 -0
- data/extconf.rb +198 -0
- data/gemspec.rb +40 -0
- data/install.rb +210 -0
- data/lib/rq.rb +155 -0
- data/lib/rq/arrayfields.rb +371 -0
- data/lib/rq/backer.rb +31 -0
- data/lib/rq/configfile.rb +82 -0
- data/lib/rq/configurator.rb +40 -0
- data/lib/rq/creator.rb +54 -0
- data/lib/rq/cron.rb +144 -0
- data/lib/rq/defaultconfig.txt +5 -0
- data/lib/rq/deleter.rb +51 -0
- data/lib/rq/executor.rb +40 -0
- data/lib/rq/feeder.rb +527 -0
- data/lib/rq/ioviewer.rb +48 -0
- data/lib/rq/job.rb +51 -0
- data/lib/rq/jobqueue.rb +947 -0
- data/lib/rq/jobrunner.rb +110 -0
- data/lib/rq/jobrunnerdaemon.rb +193 -0
- data/lib/rq/lister.rb +47 -0
- data/lib/rq/locker.rb +43 -0
- data/lib/rq/lockfile.rb +564 -0
- data/lib/rq/logging.rb +124 -0
- data/lib/rq/mainhelper.rb +189 -0
- data/lib/rq/orderedautohash.rb +39 -0
- data/lib/rq/orderedhash.rb +240 -0
- data/lib/rq/qdb.rb +733 -0
- data/lib/rq/querier.rb +98 -0
- data/lib/rq/rails.rb +80 -0
- data/lib/rq/recoverer.rb +28 -0
- data/lib/rq/refresher.rb +80 -0
- data/lib/rq/relayer.rb +283 -0
- data/lib/rq/resource.rb +22 -0
- data/lib/rq/resourcemanager.rb +40 -0
- data/lib/rq/resubmitter.rb +100 -0
- data/lib/rq/rotater.rb +98 -0
- data/lib/rq/sleepcycle.rb +46 -0
- data/lib/rq/snapshotter.rb +40 -0
- data/lib/rq/sqlite.rb +286 -0
- data/lib/rq/statuslister.rb +48 -0
- data/lib/rq/submitter.rb +113 -0
- data/lib/rq/toucher.rb +182 -0
- data/lib/rq/updater.rb +94 -0
- data/lib/rq/usage.rb +1222 -0
- data/lib/rq/util.rb +304 -0
- data/rdoc.sh +17 -0
- data/rq-ruby1.8.gemspec +120 -0
- data/test/.gitignore +1 -0
- data/test/test_rq.rb +145 -0
- data/white_box/crontab +2 -0
- data/white_box/joblist +8 -0
- data/white_box/killrq +18 -0
- data/white_box/rq_killer +27 -0
- metadata +208 -0
data/lib/rq/logging.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
unless defined? $__rq_logging__
|
2
|
+
module RQ
|
3
|
+
#--{{{
|
4
|
+
LIBDIR = File::dirname(File::expand_path(__FILE__)) + File::SEPARATOR unless
|
5
|
+
defined? LIBDIR
|
6
|
+
|
7
|
+
require "logger"
|
8
|
+
|
9
|
+
require LIBDIR + 'util'
|
10
|
+
#
|
11
|
+
# module which adds logging methods to all RQ classes
|
12
|
+
#
|
13
|
+
module Logging
|
14
|
+
#--{{{
|
15
|
+
#
|
16
|
+
# a module that adds an accessor to Logging objects in ored to fix a bug where
|
17
|
+
# not all logging devices are put into sync mode, resulting in improper log
|
18
|
+
# rolling. this is a hack.
|
19
|
+
#
|
20
|
+
module LoggerExt
|
21
|
+
#--{{{
|
22
|
+
attr :logdev
|
23
|
+
#--}}}
|
24
|
+
end # module LoggerExt
|
25
|
+
#
|
26
|
+
# implementations of the methods shared by both classes and objects of classes
|
27
|
+
# which include Logging
|
28
|
+
#
|
29
|
+
module LogMethods
|
30
|
+
#--{{{
|
31
|
+
def logger
|
32
|
+
#--{{{
|
33
|
+
if defined?(@logger) and @logger
|
34
|
+
@logger
|
35
|
+
else
|
36
|
+
if Class === self
|
37
|
+
@logger = self.default_logger
|
38
|
+
else
|
39
|
+
@logger = self::class::logger
|
40
|
+
end
|
41
|
+
raise "@logger is undefined!" unless defined?(@logger) and @logger
|
42
|
+
@logger
|
43
|
+
end
|
44
|
+
#--}}}
|
45
|
+
end
|
46
|
+
def logger= log
|
47
|
+
#--{{{
|
48
|
+
@logger = log
|
49
|
+
@logger.extend LoggerExt
|
50
|
+
@logger.logdev.dev.sync = true
|
51
|
+
@logger
|
52
|
+
#--}}}
|
53
|
+
end
|
54
|
+
def debug(*args, &block); logger.debug(*args, &block); end
|
55
|
+
def info(*args, &block); logger.info(*args, &block) ; end
|
56
|
+
def warn(*args, &block); logger.warn(*args, &block) ; end
|
57
|
+
def error(*args, &block); logger.error(*args, &block); end
|
58
|
+
def fatal(*args, &block); logger.fatal(*args, &block); end
|
59
|
+
def logerr e
|
60
|
+
#--{{{
|
61
|
+
if logger.debug?
|
62
|
+
error{ Util::errmsg e }
|
63
|
+
else
|
64
|
+
error{ Util::emsg e }
|
65
|
+
end
|
66
|
+
#--}}}
|
67
|
+
end
|
68
|
+
#--}}}
|
69
|
+
end # module LogMethods
|
70
|
+
|
71
|
+
module LogClassMethods
|
72
|
+
#--{{{
|
73
|
+
def default_logger
|
74
|
+
#--{{{
|
75
|
+
if defined?(@default_logger) and @default_logger
|
76
|
+
@default_logger
|
77
|
+
else
|
78
|
+
self.default_logger = Logger::new STDERR
|
79
|
+
@default_logger = Logger::INFO
|
80
|
+
@default_logger.warn{ "<#{ self }> using default logger"}
|
81
|
+
@default_logger
|
82
|
+
end
|
83
|
+
#--}}}
|
84
|
+
end
|
85
|
+
def default_logger= log
|
86
|
+
#--{{{
|
87
|
+
@default_logger = (Logger === log ? log : Logger::new(log))
|
88
|
+
@default_logger.extend LoggerExt
|
89
|
+
@default_logger.logdev.dev.sync = true
|
90
|
+
@default_logger
|
91
|
+
#--}}}
|
92
|
+
end
|
93
|
+
#--}}}
|
94
|
+
end
|
95
|
+
|
96
|
+
EOL = "\n"
|
97
|
+
DIV0 = ("." * 79) << EOL
|
98
|
+
DIV1 = ("-" * 79) << EOL
|
99
|
+
DIV2 = ("=" * 79) << EOL
|
100
|
+
DIV3 = ("#" * 79) << EOL
|
101
|
+
SEC0 = ("." * 16) << EOL
|
102
|
+
SEC1 = ("-" * 16) << EOL
|
103
|
+
SEC2 = ("=" * 16) << EOL
|
104
|
+
SEC3 = ("#" * 16) << EOL
|
105
|
+
|
106
|
+
class << self
|
107
|
+
#--{{{
|
108
|
+
def append_features c
|
109
|
+
#--{{{
|
110
|
+
ret = super
|
111
|
+
c.extend LogMethods
|
112
|
+
c.extend LogClassMethods
|
113
|
+
ret
|
114
|
+
#--}}}
|
115
|
+
end
|
116
|
+
#--}}}
|
117
|
+
end
|
118
|
+
include LogMethods
|
119
|
+
#--}}}
|
120
|
+
end # module Logging
|
121
|
+
#--}}}
|
122
|
+
end # module rq
|
123
|
+
$__rq_logging__ = __FILE__
|
124
|
+
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
unless defined? $__rq_mainhelper__
|
2
|
+
module RQ
|
3
|
+
#--{{{
|
4
|
+
LIBDIR = File::dirname(File::expand_path(__FILE__)) + File::SEPARATOR unless
|
5
|
+
defined? LIBDIR
|
6
|
+
|
7
|
+
require 'tempfile'
|
8
|
+
|
9
|
+
require LIBDIR + 'util'
|
10
|
+
require LIBDIR + 'logging'
|
11
|
+
|
12
|
+
#
|
13
|
+
# the MainHelper class abstracts some of the common functions the various
|
14
|
+
# Main delegates require
|
15
|
+
#
|
16
|
+
class MainHelper
|
17
|
+
#--{{{
|
18
|
+
include Util
|
19
|
+
include Logging
|
20
|
+
attr :main
|
21
|
+
attr :argv
|
22
|
+
attr :env
|
23
|
+
attr :program
|
24
|
+
attr :stdin
|
25
|
+
attr :job_stdin
|
26
|
+
attr :cmd
|
27
|
+
attr :options
|
28
|
+
attr :qpath
|
29
|
+
attr :mode
|
30
|
+
attr :quiet
|
31
|
+
attr :q
|
32
|
+
attr :fields
|
33
|
+
attr :dot_rq_dir
|
34
|
+
attr :loops
|
35
|
+
|
36
|
+
alias_method 'stdin?', 'stdin'
|
37
|
+
alias_method 'job_stdin?', 'job_stdin'
|
38
|
+
alias_method 'quiet?', 'quiet'
|
39
|
+
def initialize main
|
40
|
+
#--{{{
|
41
|
+
@main = main
|
42
|
+
@logger = main.logger
|
43
|
+
@argv = main.argv
|
44
|
+
@env = main.env
|
45
|
+
@program = main.program
|
46
|
+
@stdin = main.stdin
|
47
|
+
@data = main.data
|
48
|
+
@job_stdin = main.job_stdin
|
49
|
+
@cmd = main.cmd
|
50
|
+
@options = main.options
|
51
|
+
@qpath = main.qpath
|
52
|
+
@mode = main.mode
|
53
|
+
@quiet = main.quiet
|
54
|
+
@fields = main.fields
|
55
|
+
@dot_rq_dir = main.dot_rq_dir
|
56
|
+
@loops = main.loops
|
57
|
+
@q = nil
|
58
|
+
#--}}}
|
59
|
+
end
|
60
|
+
def set_q
|
61
|
+
#--{{{
|
62
|
+
raise "q <#{ @qpath }> does not exist" unless test ?d, @qpath
|
63
|
+
@q = JobQueue::new @qpath, 'logger' => @logger
|
64
|
+
if @options['snapshot']
|
65
|
+
ss = "#{ $0 }_#{ Process::pid }_#{ Thread::current.object_id.abs }_#{ rand Time::now.to_i }".gsub(%r|/|o,'_')
|
66
|
+
qtmp = File::join Dir::tmpdir, ss
|
67
|
+
@q = @q.snapshot qtmp, @options['retries']
|
68
|
+
at_exit{ FileUtils::rm_rf qtmp }
|
69
|
+
end
|
70
|
+
#--}}}
|
71
|
+
end
|
72
|
+
def loadio io, path, jobs
|
73
|
+
#--{{{
|
74
|
+
while((line = io.gets))
|
75
|
+
if line =~ %r/^---\s*$/o
|
76
|
+
loaded = YAML::load io
|
77
|
+
raise "no jobs in <#{ path }>" unless
|
78
|
+
Array === loaded and
|
79
|
+
Hash === loaded.first and Hash === loaded.last
|
80
|
+
loaded.each{|job| jobs << job}
|
81
|
+
loaded = nil
|
82
|
+
else
|
83
|
+
# line.gsub!(%r/(?:^\s+)|(?:\s+$)|(?:#.*$)/o, '')
|
84
|
+
line.strip!
|
85
|
+
next if line.empty?
|
86
|
+
job = Job::new
|
87
|
+
if((m = %r/^\s*(?:jid\s*=\s*)?(\d+)\s*$/io.match(line)))
|
88
|
+
job['jid'] = Integer(m[1])
|
89
|
+
else
|
90
|
+
job['command'] = line
|
91
|
+
end
|
92
|
+
jobs << job
|
93
|
+
end
|
94
|
+
end
|
95
|
+
#--}}}
|
96
|
+
end
|
97
|
+
def loadio io, path, jobs
|
98
|
+
#--{{{
|
99
|
+
while((line = io.gets))
|
100
|
+
if line =~ %r/^---\s*$/o
|
101
|
+
loadyaml io, path, jobs
|
102
|
+
else
|
103
|
+
# line.gsub!(%r/(?:^\s+)|(?:\s+$)|(?:#.*$)/o, '')
|
104
|
+
line.strip!
|
105
|
+
next if line.empty?
|
106
|
+
job = Job::new
|
107
|
+
if((m = %r/^\s*(?:jid\s*=\s*)?(\d+)\s*$/io.match(line)))
|
108
|
+
job['jid'] = Integer(m[1])
|
109
|
+
else
|
110
|
+
job['command'] = line
|
111
|
+
end
|
112
|
+
jobs << job
|
113
|
+
end
|
114
|
+
end
|
115
|
+
#--}}}
|
116
|
+
end
|
117
|
+
def loadyaml io, path, jobs
|
118
|
+
#--{{{
|
119
|
+
h = nil
|
120
|
+
while((line = io.gets))
|
121
|
+
line.strip!
|
122
|
+
next if line.empty?
|
123
|
+
case line
|
124
|
+
when %r/^\s*-\s*$/
|
125
|
+
jobs << h if h
|
126
|
+
h = {}
|
127
|
+
else
|
128
|
+
k, v = line.split %r/:/, 2
|
129
|
+
k.strip!
|
130
|
+
v.strip!
|
131
|
+
h[k] = v
|
132
|
+
end
|
133
|
+
end
|
134
|
+
jobs << h if h
|
135
|
+
#--}}}
|
136
|
+
end
|
137
|
+
def dumping_yaml_tuples
|
138
|
+
#--{{{
|
139
|
+
fields = nil
|
140
|
+
dump = lambda do |tuple|
|
141
|
+
puts '---'
|
142
|
+
if fields.nil?
|
143
|
+
if @fields
|
144
|
+
fields = field_match @fields, tuple.fields
|
145
|
+
else
|
146
|
+
fields = tuple.fields
|
147
|
+
end
|
148
|
+
end
|
149
|
+
dump = lambda do |tuple|
|
150
|
+
puts '-'
|
151
|
+
fields.each{|f| puts " #{ f }: #{ tuple[ f ] }"}
|
152
|
+
end
|
153
|
+
dump[tuple]
|
154
|
+
end
|
155
|
+
lambda{|tuple| dump[tuple]}
|
156
|
+
#--}}}
|
157
|
+
end
|
158
|
+
def field_match srclist, dstlist
|
159
|
+
#--{{{
|
160
|
+
fields = dstlist.select do |dst|
|
161
|
+
srclist.map do |src|
|
162
|
+
re =
|
163
|
+
if src =~ %r/^[a-zA-Z0-9_-]+$/
|
164
|
+
%r/^#{ src }/i
|
165
|
+
else
|
166
|
+
%r/#{ src }/i
|
167
|
+
end
|
168
|
+
src == dst or dst =~ re
|
169
|
+
end.any?
|
170
|
+
end.uniq
|
171
|
+
#--}}}
|
172
|
+
end
|
173
|
+
def init_job_stdin!
|
174
|
+
#--{{{
|
175
|
+
if @job_stdin == '-'
|
176
|
+
tmp = Tempfile::new "#{ Process::pid }_#{ rand 42 }"
|
177
|
+
while((buf = STDIN.read(8192))); tmp.write buf; end
|
178
|
+
tmp.close
|
179
|
+
@job_stdin = tmp.path
|
180
|
+
end
|
181
|
+
@job_stdin
|
182
|
+
#--}}}
|
183
|
+
end
|
184
|
+
#--}}}
|
185
|
+
end # class MainHelper
|
186
|
+
#--}}}
|
187
|
+
end # module RQ
|
188
|
+
$__rq_mainhelper__ = __FILE__
|
189
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
unless defined? $__rq_orderedautohash__
|
2
|
+
module RQ
|
3
|
+
#--{{{
|
4
|
+
LIBDIR = File::dirname(File::expand_path(__FILE__)) + File::SEPARATOR unless
|
5
|
+
defined? LIBDIR
|
6
|
+
|
7
|
+
require LIBDIR + 'orderedhash'
|
8
|
+
|
9
|
+
#if false
|
10
|
+
class ::OrderedHash
|
11
|
+
#--{{{
|
12
|
+
def initialize(*a, &b)
|
13
|
+
#--{{{
|
14
|
+
super
|
15
|
+
@order = []
|
16
|
+
#--}}}
|
17
|
+
end
|
18
|
+
#--}}}
|
19
|
+
end
|
20
|
+
#end
|
21
|
+
|
22
|
+
class OrderedAutoHash < ::OrderedHash
|
23
|
+
#--{{{
|
24
|
+
def initialize(*args)
|
25
|
+
#--{{{
|
26
|
+
super(*args){|a,k| a[k] = OrderedAutoHash::new(*args)}
|
27
|
+
#--}}}
|
28
|
+
end
|
29
|
+
def class
|
30
|
+
#--{{{
|
31
|
+
::Hash
|
32
|
+
#--}}}
|
33
|
+
end
|
34
|
+
#--}}}
|
35
|
+
end # class OrderedAutoHash
|
36
|
+
#--}}}
|
37
|
+
end # module RQ
|
38
|
+
$__rq_orderedautohash__ = __FILE__
|
39
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
# AUTHOR
|
2
|
+
# jan molic /mig/at/1984/dot/cz/
|
3
|
+
#
|
4
|
+
# DESCRIPTION
|
5
|
+
# Hash with preserved order and some array-like extensions
|
6
|
+
# Public domain.
|
7
|
+
#
|
8
|
+
# THANKS
|
9
|
+
# Andrew Johnson for his suggestions and fixes of Hash[],
|
10
|
+
# merge, to_a, inspect and shift
|
11
|
+
#
|
12
|
+
# USAGE
|
13
|
+
# just require this file and use OrderedHash instead of Hash (examples are at the end)
|
14
|
+
# you can try to run this file (ruby orderedhash.rb)
|
15
|
+
#
|
16
|
+
|
17
|
+
class OrderedHash < Hash
|
18
|
+
|
19
|
+
attr_accessor :order
|
20
|
+
|
21
|
+
class << self
|
22
|
+
def [] *args
|
23
|
+
hsh = OrderedHash.new
|
24
|
+
if Hash === args[0]
|
25
|
+
hsh.replace args[0]
|
26
|
+
elsif (args.size % 2) != 0
|
27
|
+
raise ArgumentError, "odd number of elements for Hash"
|
28
|
+
else
|
29
|
+
hsh[args.shift] = args.shift while args.size > 0
|
30
|
+
end
|
31
|
+
hsh
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize
|
36
|
+
@order = []
|
37
|
+
end
|
38
|
+
|
39
|
+
def store_only a,b
|
40
|
+
store a,b
|
41
|
+
end
|
42
|
+
|
43
|
+
alias orig_store store
|
44
|
+
def store a,b
|
45
|
+
@order.push a unless has_key? a
|
46
|
+
super a,b
|
47
|
+
end
|
48
|
+
alias []= store
|
49
|
+
|
50
|
+
def == hsh2
|
51
|
+
return false if @order != hsh2.order
|
52
|
+
super hsh2
|
53
|
+
end
|
54
|
+
|
55
|
+
def clear
|
56
|
+
@order = []
|
57
|
+
super
|
58
|
+
end
|
59
|
+
|
60
|
+
def delete key
|
61
|
+
@order.delete key
|
62
|
+
super
|
63
|
+
end
|
64
|
+
|
65
|
+
def each_key
|
66
|
+
@order.each { |k| yield k }
|
67
|
+
self
|
68
|
+
end
|
69
|
+
|
70
|
+
def each_value
|
71
|
+
@order.each { |k| yield self[k] }
|
72
|
+
self
|
73
|
+
end
|
74
|
+
|
75
|
+
def each
|
76
|
+
@order.each { |k| yield k,self[k] }
|
77
|
+
self
|
78
|
+
end
|
79
|
+
alias each_pair each
|
80
|
+
|
81
|
+
def delete_if
|
82
|
+
@order.clone.each { |k|
|
83
|
+
delete k if yield
|
84
|
+
}
|
85
|
+
self
|
86
|
+
end
|
87
|
+
|
88
|
+
def values
|
89
|
+
ary = []
|
90
|
+
@order.each { |k| ary.push self[k] }
|
91
|
+
ary
|
92
|
+
end
|
93
|
+
|
94
|
+
def keys
|
95
|
+
@order
|
96
|
+
end
|
97
|
+
|
98
|
+
def invert
|
99
|
+
hsh2 = Hash.new
|
100
|
+
@order.each { |k| hsh2[self[k]] = k }
|
101
|
+
hsh2
|
102
|
+
end
|
103
|
+
|
104
|
+
def reject &block
|
105
|
+
self.dup.delete_if &block
|
106
|
+
end
|
107
|
+
|
108
|
+
def reject! &block
|
109
|
+
hsh2 = reject &block
|
110
|
+
self == hsh2 ? nil : hsh2
|
111
|
+
end
|
112
|
+
|
113
|
+
def replace hsh2
|
114
|
+
@order = hsh2.keys
|
115
|
+
super hsh2
|
116
|
+
end
|
117
|
+
|
118
|
+
def shift
|
119
|
+
key = @order.first
|
120
|
+
key ? [key,delete(key)] : super
|
121
|
+
end
|
122
|
+
|
123
|
+
def unshift k,v
|
124
|
+
unless self.include? k
|
125
|
+
@order.unshift k
|
126
|
+
orig_store(k,v)
|
127
|
+
true
|
128
|
+
else
|
129
|
+
false
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def push k,v
|
134
|
+
unless self.include? k
|
135
|
+
@order.push k
|
136
|
+
orig_store(k,v)
|
137
|
+
true
|
138
|
+
else
|
139
|
+
false
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def pop
|
144
|
+
key = @order.last
|
145
|
+
key ? [key,delete(key)] : nil
|
146
|
+
end
|
147
|
+
|
148
|
+
def to_a
|
149
|
+
ary = []
|
150
|
+
each { |k,v| ary << [k,v] }
|
151
|
+
ary
|
152
|
+
end
|
153
|
+
|
154
|
+
def to_s
|
155
|
+
self.to_a.to_s
|
156
|
+
end
|
157
|
+
|
158
|
+
def inspect
|
159
|
+
ary = []
|
160
|
+
each {|k,v| ary << k.inspect + "=>" + v.inspect}
|
161
|
+
'{' + ary.join(", ") + '}'
|
162
|
+
end
|
163
|
+
|
164
|
+
def update hsh2
|
165
|
+
hsh2.each { |k,v| self[k] = v }
|
166
|
+
self
|
167
|
+
end
|
168
|
+
alias :merge! update
|
169
|
+
|
170
|
+
def merge hsh2
|
171
|
+
self.dup update(hsh2)
|
172
|
+
end
|
173
|
+
|
174
|
+
def select
|
175
|
+
ary = []
|
176
|
+
each { |k,v| ary << [k,v] if yield k,v }
|
177
|
+
ary
|
178
|
+
end
|
179
|
+
|
180
|
+
attr_accessor "to_yaml_style"
|
181
|
+
def yaml_inline= bool
|
182
|
+
if respond_to?("to_yaml_style")
|
183
|
+
self.to_yaml_style = :inline
|
184
|
+
else
|
185
|
+
unless defined? @__yaml_inline_meth
|
186
|
+
@__yaml_inline_meth =
|
187
|
+
lambda {|opts|
|
188
|
+
YAML::quick_emit(object_id, opts) {|emitter|
|
189
|
+
emitter << '{ ' << map{|kv| kv.join ': '}.join(', ') << ' }'
|
190
|
+
}
|
191
|
+
}
|
192
|
+
class << self
|
193
|
+
def to_yaml opts = {}
|
194
|
+
begin
|
195
|
+
@__yaml_inline ? @__yaml_inline_meth[ opts ] : super
|
196
|
+
rescue
|
197
|
+
@to_yaml_style = :inline
|
198
|
+
super
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
@__yaml_inline = bool
|
205
|
+
end
|
206
|
+
def yaml_inline!() self.yaml_inline = true end
|
207
|
+
|
208
|
+
end
|
209
|
+
|
210
|
+
if __FILE__ == $0
|
211
|
+
|
212
|
+
# You can do simply
|
213
|
+
hsh = OrderedHash.new
|
214
|
+
hsh['z'] = 1
|
215
|
+
hsh['a'] = 2
|
216
|
+
hsh['c'] = 3
|
217
|
+
p hsh.keys # ['z','a','c']
|
218
|
+
|
219
|
+
# or using OrderedHash[] method
|
220
|
+
hsh = OrderedHash['z', 1, 'a', 2, 'c', 3]
|
221
|
+
p hsh.keys # ['z','a','c']
|
222
|
+
|
223
|
+
# but this don't preserve order
|
224
|
+
hsh = OrderedHash['z'=>1, 'a'=>2, 'c'=>3]
|
225
|
+
p hsh.keys # ['a','c','z']
|
226
|
+
|
227
|
+
# OrderedHash has useful extensions: push, pop and unshift
|
228
|
+
p hsh.push('to_end', 15) # true, key added
|
229
|
+
p hsh.push('to_end', 30) # false, already - nothing happen
|
230
|
+
p hsh.unshift('to_begin', 50) # true, key added
|
231
|
+
p hsh.unshift('to_begin', 60) # false, already - nothing happen
|
232
|
+
p hsh.keys # ["to_begin", "a", "c", "z", "to_end"]
|
233
|
+
p hsh.pop # ["to_end", 15], if nothing remains, return nil
|
234
|
+
p hsh.keys # ["to_begin", "a", "c", "z"]
|
235
|
+
p hsh.shift # ["to_begin", 30], if nothing remains, return nil
|
236
|
+
|
237
|
+
end
|
238
|
+
|
239
|
+
|
240
|
+
# END
|