alfred-workflow 1.11.3 → 2.0.0
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.
- 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
@@ -8,8 +8,8 @@ module Alfred
|
|
8
8
|
def initialize(path, opts = {})
|
9
9
|
if opts[:title]
|
10
10
|
@title = opts[:title]
|
11
|
-
elsif ['.ennote', '.webbookmark'].include? File.extname(path)
|
12
|
-
@title = %x{mdls -name kMDItemDisplayName -raw '#{path}'}
|
11
|
+
elsif ['.ennote', '.webbookmark', '.vcf', '.abcdp', '.olk14Contact'].include? File.extname(path)
|
12
|
+
@title = %x{/usr/bin/mdls -name kMDItemDisplayName -raw '#{path}'}
|
13
13
|
else
|
14
14
|
@title = File.basename(path)
|
15
15
|
end
|
@@ -24,10 +24,6 @@ module Alfred
|
|
24
24
|
super @title, opts
|
25
25
|
end
|
26
26
|
|
27
|
-
def match?(query)
|
28
|
-
all_title_match?(query)
|
29
|
-
end
|
30
|
-
|
31
27
|
end
|
32
28
|
end
|
33
29
|
end
|
data/lib/alfred/feedback/item.rb
CHANGED
@@ -63,6 +63,13 @@ module Alfred
|
|
63
63
|
send(@matcher, query)
|
64
64
|
end
|
65
65
|
|
66
|
+
#
|
67
|
+
# Matchers
|
68
|
+
#
|
69
|
+
def always_match?(query)
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
66
73
|
def title_match?(query)
|
67
74
|
return true if query.empty?
|
68
75
|
if smartcase_query(query).match(@title)
|
@@ -125,6 +132,9 @@ module Alfred
|
|
125
132
|
|
126
133
|
protected
|
127
134
|
|
135
|
+
#
|
136
|
+
# Regex helpers
|
137
|
+
#
|
128
138
|
def build_regexp(query, option)
|
129
139
|
begin
|
130
140
|
Regexp.compile(".*#{query.gsub(/\s+/,'.*')}.*", option)
|
@@ -8,7 +8,7 @@ module Alfred
|
|
8
8
|
def initialize(title, opts = {})
|
9
9
|
unless File.exist? opts[:webloc]
|
10
10
|
opts[:webloc] = ::Alfred::Util.make_webloc(
|
11
|
-
opts[:title], opts[:url],
|
11
|
+
opts[:title], opts[:url], opts[:folder])
|
12
12
|
end
|
13
13
|
|
14
14
|
@subtitle = opts[:url]
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'alfred/util'
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
require "rexml/document"
|
5
|
+
|
6
|
+
module Alfred
|
7
|
+
|
8
|
+
module Handler
|
9
|
+
class Base
|
10
|
+
Base_Invoke_Order = 100
|
11
|
+
|
12
|
+
attr_reader :status, :order
|
13
|
+
|
14
|
+
def initialize(alfred, opts = {})
|
15
|
+
@core = alfred
|
16
|
+
@order = Base_Invoke_Order
|
17
|
+
@status = :initialize
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def on_parser
|
22
|
+
;
|
23
|
+
end
|
24
|
+
|
25
|
+
def on_help
|
26
|
+
[]
|
27
|
+
end
|
28
|
+
|
29
|
+
def feedback?
|
30
|
+
true
|
31
|
+
end
|
32
|
+
def on_feedback
|
33
|
+
raise NotImplementedError
|
34
|
+
end
|
35
|
+
|
36
|
+
def action?(arg)
|
37
|
+
arg.is_a?(Hash) && arg[:handler].eql?(@settings[:handler])
|
38
|
+
end
|
39
|
+
|
40
|
+
def on_action(arg)
|
41
|
+
;
|
42
|
+
end
|
43
|
+
|
44
|
+
def on_close
|
45
|
+
;
|
46
|
+
end
|
47
|
+
|
48
|
+
def register
|
49
|
+
@core.handler_controller.register(self)
|
50
|
+
end
|
51
|
+
|
52
|
+
def <=>(other)
|
53
|
+
order <=> other.order
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
def status_message(text, exitstatus)
|
58
|
+
if exitstatus == 0
|
59
|
+
return "⭕ #{text}"
|
60
|
+
else
|
61
|
+
return "❌ #{text}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
# from alfred core
|
67
|
+
def xml_builder(arg)
|
68
|
+
@core.xml_builder(arg)
|
69
|
+
end
|
70
|
+
|
71
|
+
def options
|
72
|
+
@core.options
|
73
|
+
end
|
74
|
+
|
75
|
+
def parser
|
76
|
+
@core.query_parser
|
77
|
+
end
|
78
|
+
|
79
|
+
def query
|
80
|
+
@core.query
|
81
|
+
end
|
82
|
+
|
83
|
+
def ui
|
84
|
+
@core.ui
|
85
|
+
end
|
86
|
+
|
87
|
+
def feedback
|
88
|
+
@core.feedback
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
class Controller
|
94
|
+
## handlers are called based on handler.order
|
95
|
+
# 1-10 : critical handler
|
96
|
+
# 100 : base order
|
97
|
+
|
98
|
+
include Enumerable
|
99
|
+
|
100
|
+
def initialize
|
101
|
+
@handlers = SortedSet.new
|
102
|
+
@status = {:break => [:break, :exclusive]}
|
103
|
+
end
|
104
|
+
|
105
|
+
def register(handler)
|
106
|
+
raise InvalidArgument unless handler.is_a? ::Alfred::Handler::Base
|
107
|
+
@handlers.add(handler)
|
108
|
+
end
|
109
|
+
|
110
|
+
def empty?
|
111
|
+
@handlers.empty?
|
112
|
+
end
|
113
|
+
|
114
|
+
def each
|
115
|
+
return enum_for(__method__) unless block_given?
|
116
|
+
|
117
|
+
@handlers.each do |h|
|
118
|
+
yield(h)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def each_handler
|
123
|
+
return enum_for(__method__) unless block_given?
|
124
|
+
|
125
|
+
@handlers.each do |h|
|
126
|
+
yield(h)
|
127
|
+
break if @status[:break].include?(h.status)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'alfred/handler'
|
2
|
+
require 'fuzzy_match'
|
3
|
+
require 'amatch'
|
4
|
+
|
5
|
+
module Alfred
|
6
|
+
module Handler
|
7
|
+
|
8
|
+
class Autocomplete < Base
|
9
|
+
def initialize(alfred, opts = {})
|
10
|
+
super
|
11
|
+
@settings = {
|
12
|
+
:handler => 'Autocomplete' ,
|
13
|
+
:items => {} ,
|
14
|
+
:fuzzy_score => 0.5 ,
|
15
|
+
}.update(opts)
|
16
|
+
|
17
|
+
if @settings[:items].empty?
|
18
|
+
@load_from_workflow_setting = true
|
19
|
+
else
|
20
|
+
@load_from_workflow_setting = false
|
21
|
+
end
|
22
|
+
FuzzyMatch.engine = :amatch
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
def on_feedback
|
28
|
+
if @load_from_workflow_setting
|
29
|
+
@settings[:items].merge! @core.workflow_setting[:autocomplete]
|
30
|
+
end
|
31
|
+
|
32
|
+
before, option, tail = @core.last_option
|
33
|
+
|
34
|
+
base_item ={
|
35
|
+
:match? => :always_match? ,
|
36
|
+
:subtitle => "↩ to autocomplete" ,
|
37
|
+
:valid => 'no' ,
|
38
|
+
:icon => ::Alfred::Feedback.CoreServicesIcon('ForwardArrowIcon') ,
|
39
|
+
}
|
40
|
+
|
41
|
+
if @settings[:items].has_key? tail
|
42
|
+
unify_items(@settings[:items][tail]).each do |item|
|
43
|
+
base_item[:autocomplete] = "#{(before + [tail, item[:complete]]).join(' ')} "
|
44
|
+
feedback.add_item(base_item.update(item))
|
45
|
+
end
|
46
|
+
else
|
47
|
+
add_fuzzy_match_feedback(unify_items(@settings[:items][option]),
|
48
|
+
before, tail, base_item, feedback)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def add_fuzzy_match_feedback(items, before, query, base_item, to_feedback)
|
54
|
+
matcher = FuzzyMatch.new(items, :read => :complete)
|
55
|
+
matcher.find_all_with_score(query).each do |item, dice_similar, leven_similar|
|
56
|
+
next if item[:complete].size < query.size
|
57
|
+
|
58
|
+
if (item[:complete].start_with?(query) or
|
59
|
+
dice_similar > @settings[:fuzzy_score] or
|
60
|
+
leven_similar > @settings[:fuzzy_score])
|
61
|
+
|
62
|
+
base_item[:autocomplete] = "#{(before + [item[:complete]]).join(' ')} "
|
63
|
+
to_feedback.add_item(base_item.update(item))
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def unify_items(items)
|
69
|
+
return [] unless items
|
70
|
+
items.map do |item|
|
71
|
+
if item.is_a? String
|
72
|
+
{:title => item, :complete => item}
|
73
|
+
elsif item.is_a? Hash
|
74
|
+
unless item.has_key? :complete
|
75
|
+
item[:complete] = item[:title]
|
76
|
+
end
|
77
|
+
item
|
78
|
+
else
|
79
|
+
raise InvalidArgument, "autocomplete handler can only accept string or hash"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'moneta'
|
2
|
+
require 'alfred/util'
|
3
|
+
|
4
|
+
#
|
5
|
+
# = Alfred Callback Hander
|
6
|
+
#
|
7
|
+
# Each callback is stored using Moneta via YAML backend.!
|
8
|
+
#
|
9
|
+
# == Example:
|
10
|
+
# Suppose we have a callback with key "demo"
|
11
|
+
#
|
12
|
+
# - @backend[ENTRIES_KEY] => {
|
13
|
+
# 'demo' => {:key => 'demo', :title => 'title', :subtitle => ...}
|
14
|
+
# }
|
15
|
+
#
|
16
|
+
# - @backend['demo'] => the feedback items
|
17
|
+
#
|
18
|
+
module Alfred::Handler
|
19
|
+
|
20
|
+
class Callback < Base
|
21
|
+
ENTRIES_KEY = 'feedback_entries'
|
22
|
+
|
23
|
+
def initialize(alfred, opts = {})
|
24
|
+
super
|
25
|
+
@settings = {
|
26
|
+
:handler => 'Callback' ,
|
27
|
+
:exclusive? => true ,
|
28
|
+
:backend_dir => @core.volatile_storage_path ,
|
29
|
+
:backend_file => 'callback.yaml' ,
|
30
|
+
:handler_order => ( Base_Invoke_Order / 12 )
|
31
|
+
}.update(opts)
|
32
|
+
|
33
|
+
@order = @settings[:handler_order]
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def on_parser
|
38
|
+
parser.on("--callback [CALLBACK]", "Alfred callback feedback") do |v|
|
39
|
+
options.callback = v || ''
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def feedback?
|
44
|
+
options.callback
|
45
|
+
end
|
46
|
+
|
47
|
+
def on_feedback
|
48
|
+
return unless feedback?
|
49
|
+
if entries[options.callback]
|
50
|
+
feedback.merge! backend[options.callback]
|
51
|
+
@status = :exclusive if @settings[:exclusive?]
|
52
|
+
|
53
|
+
elsif entries.empty?
|
54
|
+
# show a warn feedback item
|
55
|
+
feedback.add_item(
|
56
|
+
{
|
57
|
+
:title => 'No available callback!' ,
|
58
|
+
:valid => 'no' ,
|
59
|
+
:autocomplete => '' ,
|
60
|
+
:subtitle => 'Please check it later. Background task may still be running.',
|
61
|
+
:icon => ::Alfred::Feedback.CoreServicesIcon('Unsupported') ,
|
62
|
+
}
|
63
|
+
)
|
64
|
+
else
|
65
|
+
# list available callbacks
|
66
|
+
entries.each do |key, entry|
|
67
|
+
feedback.add_item(
|
68
|
+
{
|
69
|
+
:title => "Feedback Callback: #{key}" ,
|
70
|
+
:subtitle => "#{entry[:timestamp]}",
|
71
|
+
:valid => 'no' ,
|
72
|
+
:autocomplete => "--callback '#{key}'" ,
|
73
|
+
:icon => ::Alfred::Feedback.CoreServicesIcon('AliasBadgeIcon') ,
|
74
|
+
}.merge(entry)
|
75
|
+
)
|
76
|
+
end
|
77
|
+
@status = :exclusive if @settings[:exclusive?]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
def on_close
|
83
|
+
backend.close
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
def on_callback(keyword, entry, feedback_items)
|
88
|
+
add_entry(entry, feedback_items)
|
89
|
+
Alfred::Util.notify("#{keyword} --callback '#{entry[:key]}'",
|
90
|
+
entry[:title] || entry[:key],
|
91
|
+
entry)
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
def add_entry(entry, feedback_items)
|
96
|
+
entry.merge!(:timestamp => Time.now)
|
97
|
+
key = entry[:key]
|
98
|
+
new_entries = entries.merge(key => entry)
|
99
|
+
backend[ENTRIES_KEY] = new_entries
|
100
|
+
backend[key] = feedback_items
|
101
|
+
end
|
102
|
+
|
103
|
+
def remove_entry(key)
|
104
|
+
new_entries = entries.delete(key)
|
105
|
+
backend[ENTRIES_KEY] = new_entries
|
106
|
+
backend.delete(key)
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
|
111
|
+
def entries
|
112
|
+
backend[ENTRIES_KEY]
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
def backend
|
117
|
+
@backend ||= Moneta.new(:YAML,
|
118
|
+
:file => File.join(@settings[:backend_dir],
|
119
|
+
@settings[:backend_file]))
|
120
|
+
|
121
|
+
unless @backend.key?(ENTRIES_KEY)
|
122
|
+
@backend[ENTRIES_KEY] = {}
|
123
|
+
end
|
124
|
+
@backend
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Alfred::Handler
|
2
|
+
|
3
|
+
class Config < Base
|
4
|
+
def initialize(alfred, opts = {})
|
5
|
+
super
|
6
|
+
@order = 20
|
7
|
+
@settings = {
|
8
|
+
:setting => alfred.workflow_setting ,
|
9
|
+
:break? => true ,
|
10
|
+
:handler => 'Config'
|
11
|
+
}.update(opts)
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
def on_parser
|
16
|
+
opts.on("-c", "--config CONFIG", "Config Workflow Settings") do |v|
|
17
|
+
options.config = v
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def on_help
|
22
|
+
{
|
23
|
+
:kind => 'text' ,
|
24
|
+
:title => '-c, --config [query]' ,
|
25
|
+
:subtitle => 'Config Workflow Settings' ,
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def on_feedback
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
require 'alfred/handler'
|
2
|
+
|
3
|
+
|
4
|
+
module Alfred
|
5
|
+
module Handler
|
6
|
+
|
7
|
+
class HelpItem < ::Hash
|
8
|
+
Base_Order = 10
|
9
|
+
def initialize(attributes = {}, &block)
|
10
|
+
super(&block)
|
11
|
+
initialize_attributes(attributes)
|
12
|
+
end
|
13
|
+
|
14
|
+
def <=>(other)
|
15
|
+
self[:order] <=> other[:order]
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def initialize_attributes(attributes)
|
21
|
+
attributes.each_pair do |att, value|
|
22
|
+
self[att] = value
|
23
|
+
end if attributes
|
24
|
+
self[:order] = Base_Order unless self[:order]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
class Help < Base
|
30
|
+
def initialize(alfred, opts = {})
|
31
|
+
super
|
32
|
+
@settings = {
|
33
|
+
:handler => 'Help' ,
|
34
|
+
:exclusive? => true ,
|
35
|
+
:with_handler_help => true ,
|
36
|
+
:items => [] ,
|
37
|
+
:handler_order => ( Base_Invoke_Order / 10 )
|
38
|
+
}.update(opts)
|
39
|
+
|
40
|
+
@order = @settings[:handler_order]
|
41
|
+
|
42
|
+
if @settings[:items].empty?
|
43
|
+
@load_from_workflow_setting = true
|
44
|
+
else
|
45
|
+
@load_from_workflow_setting = false
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
def on_parser
|
51
|
+
parser.on_tail('-?', '-h', '--help', 'Workflow Helper') do
|
52
|
+
options.help = true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def on_help
|
57
|
+
{
|
58
|
+
:kind => 'text' ,
|
59
|
+
:valid => 'no' ,
|
60
|
+
:autocomplete => '-h' ,
|
61
|
+
:match? => :always_match? ,
|
62
|
+
:order => (HelpItem::Base_Order * 12) ,
|
63
|
+
:title => '-?, -h, --help [Show Workflow Usage Help]' ,
|
64
|
+
:subtitle => 'Other feedbacks are blocked.' ,
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
def feedback?
|
69
|
+
options.help
|
70
|
+
end
|
71
|
+
|
72
|
+
def on_feedback
|
73
|
+
return unless feedback?
|
74
|
+
|
75
|
+
if @settings[:with_handler_help]
|
76
|
+
@settings[:items].push @core.on_help
|
77
|
+
@core.handler_controller.each do |h|
|
78
|
+
@settings[:items].push h.on_help
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
if @load_from_workflow_setting
|
83
|
+
if @core.workflow_setting.has_key?(:help)
|
84
|
+
@settings[:items].push @core.workflow_setting[:help]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
@settings[:items].flatten!.compact!
|
89
|
+
@settings[:items].map! { |i| HelpItem.new(i) }.sort!
|
90
|
+
|
91
|
+
@settings[:items].each do |item|
|
92
|
+
|
93
|
+
case item[:kind]
|
94
|
+
when 'file'
|
95
|
+
item[:path] = File.expand_path(item[:path])
|
96
|
+
# action is handled by fallback action in the main loop
|
97
|
+
feedback.add_file_item(item[:path], item)
|
98
|
+
when 'url'
|
99
|
+
item[:arg] = xml_builder(
|
100
|
+
:handler => @settings[:handler] ,
|
101
|
+
:kind => item[:kind] ,
|
102
|
+
:url => item[:url]
|
103
|
+
)
|
104
|
+
|
105
|
+
feedback.add_item(
|
106
|
+
{
|
107
|
+
:icon => ::Alfred::Feedback.CoreServicesIcon('BookmarkIcon')
|
108
|
+
}.merge(item)
|
109
|
+
)
|
110
|
+
|
111
|
+
when 'text', 'message'
|
112
|
+
item[:arg] = xml_builder(
|
113
|
+
{
|
114
|
+
:handler => @settings[:handler] ,
|
115
|
+
:kind => item[:kind] ,
|
116
|
+
}
|
117
|
+
)
|
118
|
+
|
119
|
+
feedback.add_item(
|
120
|
+
{
|
121
|
+
:valid => 'no' ,
|
122
|
+
:autocomplete => '' ,
|
123
|
+
:icon => ::Alfred::Feedback.CoreServicesIcon('ClippingText') ,
|
124
|
+
}.merge(item)
|
125
|
+
)
|
126
|
+
|
127
|
+
else
|
128
|
+
if item.has_key? :title
|
129
|
+
item[:arg] = xml_builder(
|
130
|
+
{
|
131
|
+
:handler => @settings[:handler] ,
|
132
|
+
:kind => item[:kind] ,
|
133
|
+
}.merge(item)
|
134
|
+
)
|
135
|
+
|
136
|
+
feedback.add_item(
|
137
|
+
{
|
138
|
+
:icon => ::Alfred::Feedback.CoreServicesIcon('HelpIcon'),
|
139
|
+
}.merge(item)
|
140
|
+
)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
@status = :exclusive if @settings[:exclusive?]
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
def on_action(arg)
|
150
|
+
return unless action?(arg)
|
151
|
+
|
152
|
+
case arg[:kind]
|
153
|
+
when 'url'
|
154
|
+
::Alfred::Util.open_url(arg[:url])
|
155
|
+
when 'file'
|
156
|
+
%x{open "#{arg[:path]}"}
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
end
|