alfred-workflow 1.11.3 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -7
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/Gemfile.lock +45 -28
- data/Guardfile +4 -4
- data/History.txt +142 -0
- data/Manifest.txt +7 -0
- data/README.md +19 -1
- data/Rakefile +6 -4
- data/alfred-workflow.gemspec +27 -9
- data/lib/alfred.rb +275 -47
- data/lib/alfred/feedback.rb +112 -24
- data/lib/alfred/feedback/file_item.rb +2 -6
- data/lib/alfred/feedback/item.rb +10 -0
- data/lib/alfred/feedback/webloc_item.rb +1 -1
- data/lib/alfred/handler.rb +133 -0
- data/lib/alfred/handler/autocomplete.rb +86 -0
- data/lib/alfred/handler/callback.rb +130 -0
- data/lib/alfred/handler/cofig.rb +33 -0
- data/lib/alfred/handler/help.rb +162 -0
- data/lib/alfred/osx.rb +63 -0
- data/lib/alfred/setting.rb +29 -73
- data/lib/alfred/ui.rb +1 -0
- data/lib/alfred/util.rb +53 -5
- data/lib/alfred/version.rb +1 -1
- data/spec/alfred/feedback_spec.rb +8 -8
- data/spec/alfred/setting_spec.rb +44 -50
- data/spec/alfred_spec.rb +2 -10
- data/test/workflow/setting.yaml +2 -1
- metadata +304 -135
- metadata.gz.sig +1 -3
data/lib/alfred.rb
CHANGED
@@ -3,10 +3,15 @@ require 'rubygems' unless defined? Gem # rubygems is only needed in 1.8
|
|
3
3
|
require 'plist'
|
4
4
|
require 'fileutils'
|
5
5
|
require 'yaml'
|
6
|
+
require 'optparse'
|
7
|
+
require 'ostruct'
|
8
|
+
require 'gyoku'
|
9
|
+
require 'nori'
|
6
10
|
|
7
11
|
require 'alfred/ui'
|
8
12
|
require 'alfred/feedback'
|
9
13
|
require 'alfred/setting'
|
14
|
+
require 'alfred/handler/help'
|
10
15
|
|
11
16
|
module Alfred
|
12
17
|
|
@@ -18,15 +23,33 @@ module Alfred
|
|
18
23
|
|
19
24
|
class ObjCError < AlfredError; status_code(1) ; end
|
20
25
|
class NoBundleIDError < AlfredError; status_code(2) ; end
|
26
|
+
class InvalidArgument < AlfredError; status_code(10) ; end
|
21
27
|
class InvalidFormat < AlfredError; status_code(11) ; end
|
22
28
|
class NoMethodError < AlfredError; status_code(13) ; end
|
23
29
|
class PathError < AlfredError; status_code(14) ; end
|
24
30
|
|
25
31
|
class << self
|
26
32
|
|
33
|
+
#
|
34
|
+
# Default entry point to build alfred workflow with this gem
|
35
|
+
#
|
36
|
+
# Example:
|
37
|
+
#
|
38
|
+
# class MyHandler < ::Alfred::Handler::Base
|
39
|
+
# # ......
|
40
|
+
# end
|
41
|
+
# Alfred.with_friendly_error do |alfred|
|
42
|
+
# alfred.with_rescue_feedback = true
|
43
|
+
# alfred.with_help_feedback = true
|
44
|
+
# MyHandler.new(alfred).register
|
45
|
+
# end
|
46
|
+
#
|
27
47
|
def with_friendly_error(alfred = Alfred::Core.new, &blk)
|
28
48
|
begin
|
49
|
+
|
29
50
|
yield alfred
|
51
|
+
alfred.start_handler
|
52
|
+
|
30
53
|
rescue AlfredError => e
|
31
54
|
alfred.ui.error e.message
|
32
55
|
alfred.ui.debug e.backtrace.join("\n")
|
@@ -42,6 +65,8 @@ module Alfred
|
|
42
65
|
rescue SystemExit => e
|
43
66
|
puts alfred.rescue_feedback(
|
44
67
|
:title => "SystemExit: #{e.status}") if alfred.with_rescue_feedback
|
68
|
+
alfred.ui.error e.message
|
69
|
+
alfred.ui.debug e.backtrace.join("\n")
|
45
70
|
exit e.status
|
46
71
|
rescue Exception => e
|
47
72
|
alfred.ui.error(
|
@@ -83,41 +108,190 @@ __APPLESCRIPT__}.chop
|
|
83
108
|
end
|
84
109
|
|
85
110
|
class Core
|
86
|
-
attr_accessor :with_rescue_feedback
|
87
|
-
attr_accessor :
|
111
|
+
attr_accessor :with_rescue_feedback, :with_help_feedback
|
112
|
+
attr_accessor :cached_feedback_reload_option
|
88
113
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
@
|
114
|
+
attr_reader :handler_controller
|
115
|
+
attr_reader :query, :raw_query
|
116
|
+
|
117
|
+
|
118
|
+
def initialize(&blk)
|
119
|
+
@with_rescue_feedback = true
|
120
|
+
@with_help_feedback = false
|
121
|
+
@cached_feedback_reload_option = {
|
122
|
+
:use_reload_option => false,
|
123
|
+
:use_exclamation_mark => false
|
124
|
+
}
|
125
|
+
|
126
|
+
@query = ARGV
|
127
|
+
@raw_query = ARGV.dup
|
128
|
+
|
129
|
+
@handler_controller = ::Alfred::Handler::Controller.new
|
95
130
|
|
96
131
|
instance_eval(&blk) if block_given?
|
132
|
+
|
133
|
+
raise NoBundleIDError unless bundle_id
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
def debug?
|
138
|
+
ui.level >= LogUI::WARN
|
139
|
+
end
|
140
|
+
|
141
|
+
#
|
142
|
+
# Main loop to work with handlers
|
143
|
+
#
|
144
|
+
def start_handler
|
145
|
+
|
146
|
+
if @with_help_feedback
|
147
|
+
::Alfred::Handler::Help.new(self, :with_handler_help => true).register
|
148
|
+
end
|
149
|
+
|
150
|
+
return if @handler_controller.empty?
|
151
|
+
|
152
|
+
# step 1: register option parser for handlers
|
153
|
+
@handler_controller.each do |handler|
|
154
|
+
handler.on_parser
|
155
|
+
end
|
156
|
+
|
157
|
+
begin
|
158
|
+
query_parser.parse!
|
159
|
+
rescue OptionParser::InvalidOption, OptionParser::MissingArgument => e
|
160
|
+
ui.warn(
|
161
|
+
"Fail to parse user query.\n" \
|
162
|
+
" #{e.inspect}\n #{e.backtrace.join(" \n")}\n") if debug?
|
163
|
+
end
|
164
|
+
|
165
|
+
if @cached_feedback_reload_option[:use_exclamation_mark] && !options.should_reload_cached_feedback
|
166
|
+
if ARGV[0].eql?('!')
|
167
|
+
ARGV.shift
|
168
|
+
options.should_reload_cached_feedback = true
|
169
|
+
elsif ARGV[-1].eql?('!')
|
170
|
+
ARGV.delete_at(-1)
|
171
|
+
options.should_reload_cached_feedback = true
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
@query = ARGV
|
176
|
+
|
177
|
+
# step 2: dispatch options to handler for FEEDBACK or ACTION
|
178
|
+
case options.workflow_mode
|
179
|
+
when :feedback
|
180
|
+
@handler_controller.each_handler do |handler|
|
181
|
+
handler.on_feedback
|
182
|
+
end
|
183
|
+
|
184
|
+
puts feedback.to_alfred(@query)
|
185
|
+
when :action
|
186
|
+
arg = @query
|
187
|
+
if @query.length == 1
|
188
|
+
if hsh = xml_parser(@query[0])
|
189
|
+
arg = hsh
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
if arg.is_a?(Hash)
|
194
|
+
@handler_controller.each_handler do |handler|
|
195
|
+
handler.on_action(arg)
|
196
|
+
end
|
197
|
+
else
|
198
|
+
#fallback default action
|
199
|
+
arg.each do |a|
|
200
|
+
if File.exist? a
|
201
|
+
%x{open "#{a}"}
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
else
|
206
|
+
raise InvalidArgument, "#{options.workflow_mode} mode is not supported."
|
207
|
+
end
|
208
|
+
|
209
|
+
# step 3: close
|
210
|
+
close
|
211
|
+
@handler_controller.each_handler do |handler|
|
212
|
+
handler.on_close
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|
216
|
+
|
217
|
+
def close
|
218
|
+
@feedback.close if @feedback
|
219
|
+
@setting.close if @setting
|
220
|
+
# @workflow_setting.close if @workflow_setting
|
221
|
+
end
|
222
|
+
|
223
|
+
|
224
|
+
#
|
225
|
+
# Parse and return user query to three parts
|
226
|
+
#
|
227
|
+
# [ [before], last option, tail ]
|
228
|
+
#
|
229
|
+
def last_option
|
230
|
+
(@raw_query.size - 1).downto(0) do |i|
|
231
|
+
if @raw_query[i].start_with? '-'
|
232
|
+
if @raw_query[i] == @raw_query[-1]
|
233
|
+
return @raw_query[0...i], '', @raw_query[i]
|
234
|
+
else
|
235
|
+
return @raw_query[0..i], @raw_query[i], @raw_query[(i + 1)..-1].join(' ')
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
return [], '', @raw_query.join(' ')
|
241
|
+
end
|
242
|
+
|
243
|
+
def options(opts = {})
|
244
|
+
@options ||= OpenStruct.new(opts)
|
245
|
+
end
|
246
|
+
|
247
|
+
def query_parser
|
248
|
+
@query_parser ||= init_query_parser
|
249
|
+
end
|
250
|
+
|
251
|
+
def xml_parser(xml)
|
252
|
+
@xml_parser ||= Nori.new(:parser => :rexml,
|
253
|
+
:convert_tags_to => lambda { |tag| tag.to_sym })
|
254
|
+
begin
|
255
|
+
hsh = @xml_parser.parse(xml)
|
256
|
+
return hsh[:root]
|
257
|
+
rescue REXML::ParseException, Nokogiri::XML::SyntaxError
|
258
|
+
return nil
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
def xml_builder(arg)
|
263
|
+
Gyoku.xml(:root => arg)
|
97
264
|
end
|
98
265
|
|
99
266
|
def ui
|
100
|
-
raise NoBundleIDError unless bundle_id
|
101
267
|
@ui ||= LogUI.new(bundle_id)
|
102
268
|
end
|
103
269
|
|
104
|
-
def setting(&blk)
|
105
|
-
@setting ||= Setting.new(self, &blk)
|
106
|
-
end
|
107
270
|
|
271
|
+
#
|
272
|
+
# workflow setting is stored in the workflow_folder
|
273
|
+
#
|
108
274
|
def workflow_setting(opts = {})
|
109
|
-
@workflow_setting ||=
|
275
|
+
@workflow_setting ||= new_setting(opts)
|
110
276
|
end
|
111
277
|
|
112
|
-
|
113
|
-
|
278
|
+
#
|
279
|
+
# user setting is stored in the storage_path by default
|
280
|
+
#
|
281
|
+
def user_setting(&blk)
|
282
|
+
@setting ||= new_setting(
|
283
|
+
:file => File.join(storage_path, "setting.yaml")
|
284
|
+
)
|
114
285
|
end
|
286
|
+
alias_method :setting, :user_setting
|
115
287
|
|
116
|
-
|
117
|
-
|
118
|
-
@feedback ||=
|
288
|
+
|
289
|
+
def feedback(opts = {}, &blk)
|
290
|
+
@feedback ||= new_feedback(opts, &blk)
|
119
291
|
end
|
120
292
|
|
293
|
+
alias_method :with_cached_feedback, :feedback
|
294
|
+
|
121
295
|
def info_plist
|
122
296
|
@info_plist ||= Plist::parse_xml('info.plist')
|
123
297
|
end
|
@@ -128,9 +302,8 @@ __APPLESCRIPT__}.chop
|
|
128
302
|
end
|
129
303
|
|
130
304
|
def volatile_storage_path
|
131
|
-
raise NoBundleIDError unless bundle_id
|
132
305
|
path = "#{ENV['HOME']}/Library/Caches/com.runningwithcrayons.Alfred-2/Workflow Data/#{bundle_id}"
|
133
|
-
unless File.
|
306
|
+
unless File.directory?(path)
|
134
307
|
FileUtils.mkdir_p(path)
|
135
308
|
end
|
136
309
|
path
|
@@ -138,7 +311,6 @@ __APPLESCRIPT__}.chop
|
|
138
311
|
|
139
312
|
# Non-volatile storage directory for this bundle
|
140
313
|
def storage_path
|
141
|
-
raise NoBundleIDError unless bundle_id
|
142
314
|
path = "#{ENV['HOME']}/Library/Application Support/Alfred 2/Workflow Data/#{bundle_id}"
|
143
315
|
unless File.exist?(path)
|
144
316
|
FileUtils.mkdir_p(path)
|
@@ -147,55 +319,111 @@ __APPLESCRIPT__}.chop
|
|
147
319
|
end
|
148
320
|
|
149
321
|
|
150
|
-
def
|
151
|
-
|
152
|
-
if ws.has_key? :help
|
153
|
-
ws[:help].map do |item|
|
154
|
-
case item[:kind]
|
155
|
-
when 'url'
|
156
|
-
item[:folder] = storage_path
|
157
|
-
Feedback::UrlItem.new(item)
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|
322
|
+
def cached_feedback?
|
323
|
+
@cached_feedback_reload_option.values.any?
|
161
324
|
end
|
162
325
|
|
163
326
|
|
164
327
|
def rescue_feedback(opts = {})
|
165
328
|
default_opts = {
|
166
|
-
:title
|
167
|
-
:subtitle
|
168
|
-
:uid
|
169
|
-
:
|
170
|
-
|
171
|
-
|
172
|
-
}
|
329
|
+
:title => "Failed Query!" ,
|
330
|
+
:subtitle => "Check log #{ui.log_file} for extra debug info." ,
|
331
|
+
:uid => 'Rescue Feedback' ,
|
332
|
+
:valid => 'no' ,
|
333
|
+
:autocomplete => '' ,
|
334
|
+
:icon => Feedback.CoreServicesIcon('AlertStopIcon')
|
173
335
|
}
|
336
|
+
if @with_help_feedback
|
337
|
+
default_opts[:autocomplete] = '-h'
|
338
|
+
end
|
174
339
|
opts = default_opts.update(opts)
|
175
340
|
|
176
341
|
items = []
|
177
342
|
items << Feedback::Item.new(opts[:title], opts)
|
178
|
-
|
343
|
+
log_item = Feedback::FileItem.new(ui.log_file)
|
344
|
+
log_item.uid = nil
|
345
|
+
items << log_item
|
179
346
|
|
180
347
|
feedback.to_alfred('', items)
|
181
348
|
end
|
182
349
|
|
183
|
-
|
350
|
+
def on_help
|
351
|
+
reload_help_item
|
352
|
+
end
|
353
|
+
|
184
354
|
|
185
|
-
def
|
355
|
+
def new_feedback(opts, &blk)
|
356
|
+
::Alfred::Feedback.new(self, opts, &blk)
|
357
|
+
end
|
358
|
+
|
359
|
+
|
360
|
+
def new_setting(opts)
|
186
361
|
default_opts = {
|
187
|
-
:file => "setting.yaml",
|
362
|
+
:file => File.join(Alfred.workflow_folder, "setting.yaml"),
|
188
363
|
:format => 'yaml',
|
189
364
|
}
|
190
365
|
opts = default_opts.update(opts)
|
191
366
|
|
192
|
-
|
193
|
-
|
367
|
+
::Alfred::Setting.new(self) do
|
368
|
+
@backend_file = opts[:file]
|
369
|
+
@formt = opts[:format]
|
194
370
|
end
|
195
|
-
@workflow_setting
|
196
371
|
end
|
197
372
|
|
198
|
-
|
373
|
+
private
|
374
|
+
|
375
|
+
def reload_help_item
|
376
|
+
title = []
|
377
|
+
if @cached_feedback_reload_option[:use_exclamation_mark]
|
378
|
+
title.push "!"
|
379
|
+
end
|
380
|
+
|
381
|
+
if @cached_feedback_reload_option[:use_reload_option]
|
382
|
+
title.push "-r, --reload"
|
383
|
+
end
|
384
|
+
|
385
|
+
unless title.empty?
|
386
|
+
return {
|
387
|
+
:kind => 'text',
|
388
|
+
:order => (Handler::HelpItem::Base_Order * 10),
|
389
|
+
:title => "#{title.join(', ')} [Reload cached feedback unconditionally]" ,
|
390
|
+
:subtitle => %q{The '!' mark must be at the beginning or end of the query.} ,
|
391
|
+
}
|
392
|
+
else
|
393
|
+
return nil
|
394
|
+
end
|
395
|
+
end
|
199
396
|
|
397
|
+
def init_query_parser
|
398
|
+
options.workflow_mode = :feedback
|
399
|
+
options.modifier = :none
|
400
|
+
options.should_reload_cached_feedback = false
|
401
|
+
|
402
|
+
modifiers = [:command, :alt, :control, :shift, :fn, :none]
|
403
|
+
OptionParser.new do |opts|
|
404
|
+
opts.separator ""
|
405
|
+
opts.separator "Built-in Options:"
|
406
|
+
|
407
|
+
opts.on("--workflow-mode [TYPE]", [:feedback, :action],
|
408
|
+
"Alfred handler working mode (feedback, action)") do |t|
|
409
|
+
options.workflow_mode = t
|
410
|
+
end
|
411
|
+
|
412
|
+
opts.on("--modifier [MODIFIER]", modifiers,
|
413
|
+
"Alfred action modifier (#{modifiers})") do |t|
|
414
|
+
options.modifier = t
|
415
|
+
end
|
416
|
+
|
417
|
+
if @cached_feedback_reload_option[:use_reload_option]
|
418
|
+
opts.on("-r", "--reload", "Reload cached feedback") do
|
419
|
+
options.should_reload_cached_feedback = true
|
420
|
+
end
|
421
|
+
end
|
422
|
+
opts.separator ""
|
423
|
+
opts.separator "Handler Options:"
|
424
|
+
end
|
425
|
+
|
426
|
+
end
|
427
|
+
end
|
200
428
|
end
|
201
429
|
|
data/lib/alfred/feedback.rb
CHANGED
@@ -1,14 +1,20 @@
|
|
1
1
|
require "rexml/document"
|
2
2
|
require 'alfred/feedback/item'
|
3
3
|
require 'alfred/feedback/file_item'
|
4
|
+
require 'alfred/feedback/webloc_item'
|
4
5
|
|
5
6
|
module Alfred
|
6
7
|
|
7
8
|
class Feedback
|
8
9
|
attr_accessor :items
|
10
|
+
attr_reader :backend_file
|
9
11
|
|
10
|
-
def initialize
|
12
|
+
def initialize(alfred, opts = {}, &blk)
|
11
13
|
@items = []
|
14
|
+
@core = alfred
|
15
|
+
use_backend(opts)
|
16
|
+
instance_eval(&blk) if block_given?
|
17
|
+
|
12
18
|
end
|
13
19
|
|
14
20
|
def add_item(opts = {})
|
@@ -20,6 +26,13 @@ module Alfred
|
|
20
26
|
@items << FileItem.new(path, opts)
|
21
27
|
end
|
22
28
|
|
29
|
+
def add_webloc_item(path, opts = {})
|
30
|
+
unless opts[:folder]
|
31
|
+
opts[:folder] = @core.storage_path
|
32
|
+
end
|
33
|
+
@items << WeblocItem.new(path, opts)
|
34
|
+
end
|
35
|
+
|
23
36
|
def to_xml(with_query = '', items = @items)
|
24
37
|
document = REXML::Element.new("items")
|
25
38
|
if with_query.empty?
|
@@ -36,47 +49,122 @@ module Alfred
|
|
36
49
|
|
37
50
|
alias_method :to_alfred, :to_xml
|
38
51
|
|
52
|
+
#
|
53
|
+
# Merge with other feedback
|
54
|
+
#
|
55
|
+
def merge!(other)
|
56
|
+
if other.is_a? Array
|
57
|
+
@items |= other
|
58
|
+
elsif other.is_a? Alfred::Feedback
|
59
|
+
@items |= other.items
|
60
|
+
else
|
61
|
+
raise ArgumentError, "Feedback can not merge with #{other.class}"
|
62
|
+
end
|
63
|
+
end
|
39
64
|
|
65
|
+
#
|
66
|
+
# The workflow is about to complete
|
67
|
+
#
|
68
|
+
# - save cached feedback if necessary
|
69
|
+
#
|
70
|
+
def close
|
71
|
+
put_cached_feedback if @backend_file
|
72
|
+
end
|
40
73
|
|
41
|
-
#
|
42
|
-
|
43
|
-
|
74
|
+
#
|
75
|
+
# ## helper class method for icon
|
76
|
+
#
|
77
|
+
def self.CoreServicesIcon(name)
|
78
|
+
{
|
79
|
+
:type => "default" ,
|
80
|
+
:name => "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/#{name}.icns"
|
81
|
+
}
|
44
82
|
end
|
45
83
|
|
46
|
-
def
|
47
|
-
|
84
|
+
def self.Icon(name)
|
85
|
+
{
|
86
|
+
:type => "default" ,
|
87
|
+
:name => name ,
|
88
|
+
}
|
89
|
+
end
|
90
|
+
def self.FileIcon(path)
|
91
|
+
{
|
92
|
+
:type => "fileicon" ,
|
93
|
+
:name => path ,
|
94
|
+
}
|
48
95
|
end
|
49
|
-
end
|
50
96
|
|
51
97
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
@core = alfred
|
98
|
+
#
|
99
|
+
# ## serialization
|
100
|
+
#
|
56
101
|
|
57
|
-
|
102
|
+
def use_backend(opts = {})
|
103
|
+
@backend_file = opts[:file] if opts[:file]
|
104
|
+
@should_expire_after_second = opts[:expire].to_i if opts[:expire]
|
58
105
|
end
|
106
|
+
alias_method :use_cache_file, :use_backend
|
59
107
|
|
60
|
-
def
|
61
|
-
@
|
62
|
-
@cf_file_valid_time = opts[:expire] if opts[:expire]
|
108
|
+
def backend_file
|
109
|
+
@backend_file ||= File.join(@core.volatile_storage_path, "cached_feedback")
|
63
110
|
end
|
64
111
|
|
65
|
-
def
|
66
|
-
|
112
|
+
def expired?
|
113
|
+
return false unless @should_expire_after_second
|
114
|
+
Time.now - File.ctime(backend_file) > @should_expire_after_second
|
67
115
|
end
|
116
|
+
|
68
117
|
def get_cached_feedback
|
69
|
-
return nil unless File.exist?(
|
70
|
-
if
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
return self
|
118
|
+
return nil unless File.exist?(backend_file)
|
119
|
+
return nil if expired?
|
120
|
+
|
121
|
+
load(@backend_file)
|
122
|
+
self
|
75
123
|
end
|
76
124
|
|
77
125
|
def put_cached_feedback
|
78
|
-
dump(
|
126
|
+
dump(backend_file)
|
127
|
+
end
|
128
|
+
|
129
|
+
def dump(to_file)
|
130
|
+
File.open(to_file, "wb") { |f| Marshal.dump(@items, f) }
|
131
|
+
end
|
132
|
+
|
133
|
+
def load(from_file)
|
134
|
+
@items = File.open(from_file, "rb") { |f| Marshal.load(f) }
|
135
|
+
end
|
136
|
+
|
137
|
+
def append(from_file)
|
138
|
+
@items << File.open(from_file, "rb") { |f| Marshal.load(f) }
|
139
|
+
end
|
140
|
+
|
141
|
+
#
|
142
|
+
# Provides yaml serialization support
|
143
|
+
#
|
144
|
+
if RUBY_VERSION < "1.9"
|
145
|
+
def to_yaml_properties
|
146
|
+
[ '@items' ]
|
147
|
+
end
|
148
|
+
else
|
149
|
+
def encode_with(coder)
|
150
|
+
coder['items'] = @items
|
151
|
+
end
|
79
152
|
end
|
153
|
+
|
154
|
+
#
|
155
|
+
# Provides marshalling support for use by the Marshal library.
|
156
|
+
#
|
157
|
+
def marshal_dump
|
158
|
+
@items
|
159
|
+
end
|
160
|
+
|
161
|
+
#
|
162
|
+
# Provides marshalling support for use by the Marshal library.
|
163
|
+
#
|
164
|
+
def marshal_load(x)
|
165
|
+
@items = x
|
166
|
+
end
|
167
|
+
|
80
168
|
end
|
81
169
|
|
82
170
|
end
|