rprogram 0.0.9 → 0.1.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.
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