rprogram 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,12 @@
1
+ == 0.1.0 / 2008-01-17
2
+
3
+ * Removed redundent methods in Program:
4
+ * +Program.find_by_name+
5
+ * +Program.find_by_names+
6
+ * Added Program#create.
7
+ * Made Program Nameable by default.
8
+ * Prevented arbitrary command-injection in Program#run.
9
+
1
10
  == 0.0.9 / 2008-01-09
2
11
 
3
12
  * Initial release.
data/README.txt CHANGED
@@ -24,7 +24,7 @@ system.
24
24
 
25
25
  The MIT License
26
26
 
27
- Copyright (c) 2008 Hal Brodigan
27
+ Copyright (c) 2007-2008 Hal Brodigan
28
28
 
29
29
  Permission is hereby granted, free of charge, to any person obtaining
30
30
  a copy of this software and associated documentation files (the
data/Rakefile CHANGED
@@ -8,7 +8,7 @@ Hoe.new('rprogram', RProgram::VERSION) do |p|
8
8
  p.rubyforge_name = 'rprogram'
9
9
  p.author = 'Postmodern Modulus III'
10
10
  p.email = 'postmodern.mod3@gmail.com'
11
- p.summary = 'RProgram is a library for creating ruby wrappers around command-line programs'
11
+ p.summary = 'RProgram is a library for creating Rubyful wrappers around command-line programs'
12
12
  p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
13
13
  p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
14
14
  p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
@@ -5,27 +5,44 @@ module RProgram
5
5
  module Nameable
6
6
  def self.included(base)
7
7
  base.metaclass_eval do
8
+ #
9
+ # Returns the name of the program.
10
+ #
8
11
  def program_name
9
- @program_name
10
- end
11
-
12
- def program_name=(name)
13
- @program_name = name.to_s
12
+ @program_name ||= nil
14
13
  end
15
14
 
15
+ #
16
+ # Returns an Array of the program's aliases.
17
+ #
16
18
  def program_aliases
17
19
  @program_aliases ||= []
18
20
  end
19
21
 
20
- def program_aliases=(aliases)
21
- @program_aliases = aliases.to_a.map { |name| name.to_s }
22
+ #
23
+ # Returns an Array of all names the program is known by, combining
24
+ # both program_name and program_aliases.
25
+ #
26
+ def program_names
27
+ ([program_name] + program_aliases).compact
22
28
  end
23
29
 
24
- def find_program
25
- names = self.program_aliases
26
- names.unshift(self.program_name) if self.program_name
30
+ #
31
+ # Sets the program name for a class to the specified _name_.
32
+ #
33
+ # name_program 'ls'
34
+ #
35
+ def name_program(name)
36
+ @program_name = name.to_s
37
+ end
27
38
 
28
- return Compat.find_program_by_names(*names)
39
+ #
40
+ # Sets the program aliases for a class to the specified _aliases_.
41
+ #
42
+ # alias_program 'vim', 'vi'
43
+ #
44
+ def alias_program(*aliases)
45
+ @program_aliases = aliases.map { |name| name.to_s }
29
46
  end
30
47
  end
31
48
  end
@@ -43,25 +60,5 @@ module RProgram
43
60
  def program_aliases
44
61
  self.class.program_aliases
45
62
  end
46
-
47
- protected
48
-
49
- #
50
- # Sets the program name for a class to the specified _name_.
51
- #
52
- # name_program 'ls'
53
- #
54
- def Object.name_program(name)
55
- self.program_name = name
56
- end
57
-
58
- #
59
- # Sets the program aliases for a class to the specified _aliases_.
60
- #
61
- # name_program 'vim', 'vi'
62
- #
63
- def Object.alias_program(*aliases)
64
- self.program_aliases = aliases
65
- end
66
63
  end
67
64
  end
@@ -13,12 +13,24 @@ module RProgram
13
13
  # Can the argument be specified multiple times
14
14
  attr_reader :multiple
15
15
 
16
- def initialize(opts={:name => nil, :leading => false, :tailing => false, :multiple => false})
17
- @name = opts[:name]
18
-
19
- @leading = opts[:leading] || false
20
- @tailing = opts[:tailing] || true
21
- @multiple = opts[:multiple] || false
16
+ #
17
+ # Creates a new NonOption object with the specified _options_.
18
+ #
19
+ # _options_ may contain the following keys:
20
+ # <tt>:name</tt>:: The name of the non-option.
21
+ # <tt>:leading</tt>:: Implies the non-option is a leading non-option.
22
+ # Defaults to +false+, if not given.
23
+ # <tt>:tailing</tt>:: Implies the non-option is a tailing non-option.
24
+ # Defaults to +true+, if not given.
25
+ # <tt>:multiple</tt>:: Implies the non-option maybe given an Array
26
+ # of values. Defaults to +false+, if not given.
27
+ #
28
+ def initialize(options={})
29
+ @name = options[:name]
30
+
31
+ @leading = options[:leading] || false
32
+ @tailing = options[:tailing] || true
33
+ @multiple = options[:multiple] || false
22
34
  end
23
35
 
24
36
  def arguments(value)
@@ -10,15 +10,32 @@ module RProgram
10
10
  # Can the option be specified multiple times
11
11
  attr_reader :multiple
12
12
 
13
- def initialize(opts={:flag => nil, :equals => false, :multiple => false},&block)
14
- @flag = opts[:flag]
13
+ #
14
+ # Creates a new Option object with the specified _options_. If a _block_
15
+ # is given it will be used for the custom formating of the option. If a
16
+ # _block_ is not given, the option will use the default_format when
17
+ # generating the arguments.
18
+ #
19
+ # _options_ may contain the following keys:
20
+ # <tt>:flag</tt>:: The command-line flag to use.
21
+ # <tt>:equals</tt>:: Implies the option maybe formated as '--flag=value'.
22
+ # Defaults to +falue+, if not given.
23
+ # <tt>:multuple</tt>:: Implies the option maybe given an Array of
24
+ # values. Defaults to +false+, if not given.
25
+ #
26
+ def initialize(options={},&block)
27
+ @flag = options[:flag]
15
28
 
16
- @equals = opts[:equals] || false
17
- @multiple = opts[:multiple] || false
29
+ @equals = options[:equals] || false
30
+ @multiple = options[:multiple] || false
18
31
 
19
32
  @formating = block
20
33
  end
21
34
 
35
+ #
36
+ # Returns an +Array+ of the arguments for the option with the specified
37
+ # _value_.
38
+ #
22
39
  def arguments(value)
23
40
  return [@flag] if value==true
24
41
  return [] if (value==nil || value==false)
@@ -41,12 +58,20 @@ module RProgram
41
58
 
42
59
  protected
43
60
 
61
+ #
62
+ # Returns an Array of the flag and the specified _value_ in argument
63
+ # form.
64
+ #
44
65
  def default_format(value)
45
66
  return [@flag] + value if value.kind_of?(Array)
46
67
  return ["#{flag}=#{value}"] if @equals
47
68
  return [@flag, value]
48
69
  end
49
70
 
71
+ #
72
+ # Formats specified _value_ with the option flag using
73
+ # either the custom formating or the default_format.
74
+ #
50
75
  def format(value)
51
76
  if @formating
52
77
  return @formating.call(@flag,value).to_a
@@ -6,10 +6,17 @@ module RProgram
6
6
  module Options
7
7
  def self.included(base)
8
8
  base.metaclass_eval do
9
+ #
10
+ # Returns a Hash of all defined non-options.
11
+ #
9
12
  def non_options
10
13
  @non_options ||= {}
11
14
  end
12
15
 
16
+ #
17
+ # Returns +true+ if the non-option with the specified _name_ was
18
+ # defined, returns +false+ otherwise.
19
+ #
13
20
  def has_non_option?(name)
14
21
  name = name.to_sym
15
22
 
@@ -22,6 +29,9 @@ module RProgram
22
29
  return false
23
30
  end
24
31
 
32
+ #
33
+ # Returns the non-option known by _name_, returns +nil+ otherwise.
34
+ #
25
35
  def get_non_option(name)
26
36
  name = name.to_sym
27
37
 
@@ -34,10 +44,17 @@ module RProgram
34
44
  return nil
35
45
  end
36
46
 
47
+ #
48
+ # Returns a Hash of all defined options.
49
+ #
37
50
  def options
38
51
  @options ||= {}
39
52
  end
40
53
 
54
+ #
55
+ # Returns +true+ if an option with the specified _name_ was defined,
56
+ # returns +false+ otherwise.
57
+ #
41
58
  def has_option?(name)
42
59
  name = name.to_sym
43
60
 
@@ -50,6 +67,10 @@ module RProgram
50
67
  return false
51
68
  end
52
69
 
70
+ #
71
+ # Returns the option with the specified _name_, returns +nil+
72
+ # otherwise.
73
+ #
53
74
  def get_option(name)
54
75
  name = name.to_sym
55
76
 
@@ -64,18 +85,33 @@ module RProgram
64
85
  end
65
86
  end
66
87
 
88
+ #
89
+ # Returns +true+ if the non-option with the specified _name_ was
90
+ # defined, returns +false+ otherwise.
91
+ #
67
92
  def has_non_option?(name)
68
93
  self.class.has_non_option?(name)
69
94
  end
70
95
 
96
+ #
97
+ # Returns the non-option known by _name_, returns +nil+ otherwise.
98
+ #
71
99
  def get_non_option(name)
72
100
  self.class.get_non_option(name)
73
101
  end
74
102
 
103
+ #
104
+ # Returns +true+ if an option with the specified _name_ was defined,
105
+ # returns +false+ otherwise.
106
+ #
75
107
  def has_option?(name)
76
108
  self.class.has_option?(name)
77
109
  end
78
110
 
111
+ #
112
+ # Returns the option with the specified _name_, returns +nil+
113
+ # otherwise.
114
+ #
79
115
  def get_option(name)
80
116
  self.class.get_option(name)
81
117
  end
@@ -1,10 +1,15 @@
1
1
  require 'rprogram/compat'
2
2
  require 'rprogram/task'
3
+ require 'rprogram/nameable'
3
4
  require 'rprogram/exceptions/program_not_found'
4
5
 
6
+ require 'open3'
7
+
5
8
  module RProgram
6
9
  class Program
7
10
 
11
+ include Nameable
12
+
8
13
  # Path to the program
9
14
  attr_reader :path
10
15
 
@@ -12,62 +17,76 @@ module RProgram
12
17
  attr_reader :name
13
18
 
14
19
  #
15
- # Creates a new Program object from _path_. If _block_ is given, it will
16
- # be passed the newly created Program.
20
+ # Creates a new Program object from _path_. If _path_ is not a valid
21
+ # file, a ProgramNotFound exception will be thrown. If a _block_ is
22
+ # given, it will be passed the newly created Program.
17
23
  #
18
24
  # Program.new('/usr/bin/ls')
19
25
  #
20
26
  def initialize(path,&block)
21
- @path = File.expand_path(path)
22
- @name = File.basename(@path)
23
- end
27
+ path = File.expand_path(path)
24
28
 
25
- #
26
- # Finds the program with the specified _name_ and returns a new
27
- # Program object. If no programs could be found with the matching _name_,
28
- # a ProramNotFound exception will be raised.
29
- #
30
- # Program.find_by_name('cat') # => Program
31
- #
32
- def self.find_by_name(name)
33
- path = Compat.find_program(name)
34
- unless path
35
- raise(ProgramNotFound,"program '#{name}' could not be found",caller)
29
+ unless File.file?(path)
30
+ raise(ProgramNotFound,"program #{path.dump} does not exist",caller)
36
31
  end
37
32
 
38
- return self.new(path)
39
- end
40
-
41
- def self.find_by_names(*names)
42
- path = Compat.find_program_by_names(*names)
43
-
44
- unless path
45
- names = names.map { |name| name.dump }.join(', ')
33
+ @path = path
34
+ @name = File.basename(path)
46
35
 
47
- raise(ProgramNotFound,"programs #{names} were not be found",caller)
48
- end
49
-
50
- return self.new(path)
36
+ block.call(self) if block
51
37
  end
52
38
 
53
39
  #
54
- # Creates a new Program object with the specified _path_,
55
- # if _path_ is a valid file.
40
+ # Creates a new program object with the specified _path_, if _path_
41
+ # is a valid file. Any given _args_ or a given _block_ will be used
42
+ # in creating the new program.
56
43
  #
57
44
  # Program.create_from_path('/bin/cd') # => Program
58
45
  #
59
46
  # Program.create_from_path('/obviously/fake') # => nil
60
47
  #
61
- def self.create_from_path(path)
62
- return self.new(path) if File.file?(path)
48
+ def self.create_from_path(path,*args,&block)
49
+ return self.new(path,*args,&block) if File.file?(path)
63
50
  end
64
51
 
65
- def self.create_from_paths(*paths)
52
+ #
53
+ # Creates a new program object with the specified _paths_,
54
+ # if a path within _paths_ is a valid file. Any given _args_ or
55
+ # a given _block_ will be used in creating the new program.
56
+ #
57
+ # Program.create_from_paths(['/bin/cd','/usr/bin/cd']) # => Program
58
+ #
59
+ # Program.create_from_paths(['/obviously/fake','/bla']) # => nil
60
+ #
61
+ def self.create_from_paths(paths,*args,&block)
66
62
  paths.each do |path|
67
- return self.new(path) if File.file?(path)
63
+ return self.new(path,*args,&block) if File.file?(path)
68
64
  end
69
65
  end
70
66
 
67
+ #
68
+ # Finds and creates the program using it's +program_names+ and returns
69
+ # a new Program object. If the program cannot be found by any of it's
70
+ # +program_names+, a ProramNotFound exception will be raised. Any given
71
+ # _args_ or a given _block_ will be used in creating the new program.
72
+ #
73
+ # Program.create # => Program
74
+ #
75
+ # MyProgram.create('stuff','here') do |prog|
76
+ # ...
77
+ # end
78
+ #
79
+ def self.create(*args,&block)
80
+ path = Compat.find_program_by_names(program_names)
81
+ unless path
82
+ names = program_names.map { |name| name.dump }.join(', ')
83
+
84
+ raise(ProgramNotFound,"programs #{names} were not found",caller)
85
+ end
86
+
87
+ return self.new(path,*args,&block)
88
+ end
89
+
71
90
  #
72
91
  # Runs the program with the specified _args_ and returns
73
92
  # an Array of the programs output.
@@ -76,17 +95,17 @@ module RProgram
76
95
  # echo.run("hello") # => ["hello\n"]
77
96
  #
78
97
  def run(*args)
79
- command = [@path] + args
98
+ args = args.map { |arg| arg.to_s }
80
99
 
81
- IO.popen(command.join(' ')) do |process|
82
- return process.readlines
100
+ Open3.popen3(@path,*args) do |stdin,stdout,stderr|
101
+ return stdout.readlines
83
102
  end
84
103
  end
85
104
 
86
105
  #
87
106
  # Runs the program with the specified _task_ object.
88
107
  #
89
- def run_task(task)
108
+ def run_with_task(task)
90
109
  run(*(task.arguments))
91
110
  end
92
111
 
data/lib/rprogram/task.rb CHANGED
@@ -10,7 +10,10 @@ module RProgram
10
10
  # given, it is passed the newly created Task object.
11
11
  #
12
12
  # Task.new(:test => 'example', :count => 2, :verbose => true)
13
- # Task.new(:help => true) { |task| ... }
13
+ #
14
+ # Task.new(:help => true) do |task|
15
+ # ...
16
+ # end
14
17
  #
15
18
  def initialize(options={},&block)
16
19
  @subtasks = {}
@@ -108,7 +111,7 @@ module RProgram
108
111
  # the tasks leading non_options, options and tailing non-options.
109
112
  #
110
113
  def arguments
111
- leading_non_options + options + ['--'] + tailing_non_options
114
+ leading_non_options + options + tailing_non_options
112
115
  end
113
116
 
114
117
  protected
@@ -118,7 +121,7 @@ module RProgram
118
121
  #
119
122
  # subtask :extra, ExtraTask
120
123
  #
121
- def Object.subtask(name,task)
124
+ def self.subtask(name,task)
122
125
  class_eval %{
123
126
  def #{name}(options={},&block)
124
127
  if @subtasks[#{name.dump}]
@@ -141,7 +144,7 @@ module RProgram
141
144
  #
142
145
  # non_option :name => 'file', :tailing => true, :multiple => true
143
146
  #
144
- def Object.non_option(opts={})
147
+ def self.non_option(opts={})
145
148
  name = opts[:name].to_sym
146
149
 
147
150
  self.non_options[name] = NonOption.new(opts)
@@ -166,7 +169,7 @@ module RProgram
166
169
  #
167
170
  # long_option :flag => '-f', :name => :file
168
171
  #
169
- def Object.long_option(opts={},&block)
172
+ def self.long_option(opts={},&block)
170
173
  flag = opts[:flag].to_s
171
174
  method_name = (opts[:name] || Task.flag_namify(flag)).to_sym
172
175
 
@@ -190,7 +193,7 @@ module RProgram
190
193
  #
191
194
  # short_option :flag => '-c', :name => :count
192
195
  #
193
- def Object.short_option(opts={},&block)
196
+ def self.short_option(opts={},&block)
194
197
  method_name = opts[:name].to_sym
195
198
 
196
199
  self.options[method_name] = Option.new(opts,&block)
@@ -211,7 +214,7 @@ module RProgram
211
214
  #
212
215
  # Converts a long-option flag to a Ruby method name.
213
216
  #
214
- # Task.flag_namify('--output-file') #=> "output_files"
217
+ # Task.flag_namify('--output-file') # => "output_file"
215
218
  #
216
219
  def Task.flag_namify(flag)
217
220
  flag = flag.to_s
@@ -1,3 +1,3 @@
1
1
  module RProgram
2
- VERSION = '0.0.9'
2
+ VERSION = '0.1.0'
3
3
  end
metadata CHANGED
@@ -1,33 +1,36 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.4
3
- specification_version: 1
4
2
  name: rprogram
5
3
  version: !ruby/object:Gem::Version
6
- version: 0.0.9
7
- date: 2008-01-09 00:00:00 -08:00
8
- summary: RProgram is a library for creating ruby wrappers around command-line programs
9
- require_paths:
10
- - lib
11
- email: postmodern.mod3@gmail.com
12
- homepage: " by Postmodern Modulus III"
13
- rubyforge_project: rprogram
14
- description: "== FEATURES/PROBLEMS: * Provides cross-platform access to the PATH variable. * Supports leading/tailing non-options. * Supports long-options and short-options. * Supports custom formating of options. == INSTALL: $ sudo gem install rprogram == LICENSE:"
15
- autorequire:
16
- default_executable:
17
- bindir: bin
18
- has_rdoc: true
19
- required_ruby_version: !ruby/object:Gem::Version::Requirement
20
- requirements:
21
- - - ">"
22
- - !ruby/object:Gem::Version
23
- version: 0.0.0
24
- version:
4
+ version: 0.1.0
25
5
  platform: ruby
26
- signing_key:
27
- cert_chain:
28
- post_install_message:
29
6
  authors:
30
7
  - Postmodern Modulus III
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-01-17 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hoe
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.4.0
23
+ version:
24
+ description: "== FEATURES/PROBLEMS: * Provides cross-platform access to the PATH variable. * Supports leading/tailing non-options. * Supports long-options and short-options. * Supports custom formating of options. == INSTALL: $ sudo gem install rprogram == LICENSE:"
25
+ email: postmodern.mod3@gmail.com
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files:
31
+ - History.txt
32
+ - Manifest.txt
33
+ - README.txt
31
34
  files:
32
35
  - History.txt
33
36
  - Manifest.txt
@@ -48,28 +51,32 @@ files:
48
51
  - lib/rprogram/nameable.rb
49
52
  - lib/rprogram/program.rb
50
53
  - test/test_rprogram.rb
51
- test_files:
52
- - test/test_rprogram.rb
54
+ has_rdoc: true
55
+ homepage: " by Postmodern Modulus III"
56
+ post_install_message:
53
57
  rdoc_options:
54
58
  - --main
55
59
  - README.txt
56
- extra_rdoc_files:
57
- - History.txt
58
- - Manifest.txt
59
- - README.txt
60
- executables: []
61
-
62
- extensions: []
63
-
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ version:
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
64
74
  requirements: []
65
75
 
66
- dependencies:
67
- - !ruby/object:Gem::Dependency
68
- name: hoe
69
- version_requirement:
70
- version_requirements: !ruby/object:Gem::Version::Requirement
71
- requirements:
72
- - - ">="
73
- - !ruby/object:Gem::Version
74
- version: 1.4.0
75
- version:
76
+ rubyforge_project: rprogram
77
+ rubygems_version: 1.0.1
78
+ signing_key:
79
+ specification_version: 2
80
+ summary: RProgram is a library for creating Rubyful wrappers around command-line programs
81
+ test_files:
82
+ - test/test_rprogram.rb