cliver 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +1 -1
- data/cliver.gemspec +1 -0
- data/lib/cliver.rb +25 -2
- data/lib/cliver/assertion.rb +13 -15
- data/lib/cliver/detector.rb +14 -11
- data/lib/cliver/detector/default.rb +15 -2
- data/lib/cliver/version.rb +2 -1
- data/lib/cliver/which/posix.rb +1 -0
- data/lib/cliver/which/windows.rb +2 -1
- data/spec/cliver_spec.rb +25 -0
- metadata +3 -3
data/.travis.yml
CHANGED
data/cliver.gemspec
CHANGED
@@ -17,6 +17,7 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
|
18
18
|
spec.test_files = spec.files.grep(/^(test|spec|features)\//)
|
19
19
|
spec.require_paths = ['lib']
|
20
|
+
spec.has_rdoc = 'yard'
|
20
21
|
|
21
22
|
spec.add_development_dependency 'bundler', '~> 1.3'
|
22
23
|
spec.add_development_dependency 'rake'
|
data/lib/cliver.rb
CHANGED
@@ -5,9 +5,32 @@ require 'cliver/assertion'
|
|
5
5
|
require 'cliver/detector'
|
6
6
|
require 'cliver/detector/default'
|
7
7
|
|
8
|
+
# Cliver is tool for making dependency assertions against
|
9
|
+
# command-line executables.
|
8
10
|
module Cliver
|
9
|
-
#
|
11
|
+
# @see Cliver::Assertion
|
12
|
+
# @overload (see Cliver::Assertion#initialize)
|
13
|
+
# @param (see Cliver::Assertion#initialize)
|
14
|
+
# @raise (see Cliver::Assertion#assert!)
|
15
|
+
# @return (see Cliver::Assertion#assert!)
|
10
16
|
def self.assert(*args, &block)
|
11
|
-
Assertion.
|
17
|
+
Assertion.new(*args, &block).assert!
|
18
|
+
end
|
19
|
+
|
20
|
+
extend self
|
21
|
+
|
22
|
+
# Wraps Cliver::assert and returns truthy/false instead of raising
|
23
|
+
# @see Cliver::assert
|
24
|
+
# @overload (see Cliver::Assertion#initialize)
|
25
|
+
# @param (see Cliver::Assertion#initialize)
|
26
|
+
# @return [False,String] either returns false or the reason why the
|
27
|
+
# assertion was unmet.
|
28
|
+
def dependency_unmet?(*args, &block)
|
29
|
+
Cliver.assert(*args, &block)
|
30
|
+
false
|
31
|
+
rescue Assertion::DependencyNotMet => error
|
32
|
+
# Cliver::Assertion::VersionMismatch -> 'Version Mismatch'
|
33
|
+
reason = error.class.name.split('::').last.gsub(/(?<!\A)[A-Z]/, ' \\0')
|
34
|
+
"#{reason}: #{error.message}"
|
12
35
|
end
|
13
36
|
end
|
data/lib/cliver/assertion.rb
CHANGED
@@ -9,17 +9,14 @@ module Cliver
|
|
9
9
|
|
10
10
|
include Which # platform-specific implementation of `which`
|
11
11
|
|
12
|
+
# An exception class raised when assertion is not met
|
12
13
|
DependencyNotMet = Class.new(ArgumentError)
|
13
|
-
DependencyVersionMismatch = Class.new(DependencyNotMet)
|
14
|
-
DependencyNotFound = Class.new(DependencyNotMet)
|
15
14
|
|
16
|
-
|
15
|
+
# An exception that is raised when executable present is the wrong version
|
16
|
+
DependencyVersionMismatch = Class.new(DependencyNotMet)
|
17
17
|
|
18
|
-
#
|
19
|
-
|
20
|
-
def self.assert!(*args, &block)
|
21
|
-
new(*args, &block).assert!
|
22
|
-
end
|
18
|
+
# An exception that is raised when executable is not present
|
19
|
+
DependencyNotFound = Class.new(DependencyNotMet)
|
23
20
|
|
24
21
|
# @overload initialize(executable, *requirements, options = {})
|
25
22
|
# @param executable [String]
|
@@ -29,15 +26,13 @@ module Cliver
|
|
29
26
|
# Where <operator> is optional (default '='') and in the set
|
30
27
|
# '=', '!=', '>', '<', '>=', '<=', or '~>'
|
31
28
|
# And <version> is dot-separated integers with optional
|
32
|
-
# alphanumeric pre-release suffix
|
33
|
-
#
|
29
|
+
# alphanumeric pre-release suffix. See also
|
30
|
+
# {http://docs.rubygems.org/read/chapter/16 Specifying Versions}
|
34
31
|
# @param options [Hash<Symbol,Object>]
|
35
|
-
# @
|
32
|
+
# @option options [Cliver::Detector, #to_proc] :detector
|
36
33
|
# @yieldparam [String] full path to executable
|
37
34
|
# @yieldreturn [String] Gem::Version-parsable string version
|
38
35
|
def initialize(executable, *args, &detector)
|
39
|
-
raise ArgumentError, 'executable' unless executable[EXECUTABLE_PATTERN]
|
40
|
-
|
41
36
|
options = args.last.kind_of?(Hash) ? args.pop : {}
|
42
37
|
|
43
38
|
@executable = executable.dup.freeze
|
@@ -49,14 +44,17 @@ module Cliver
|
|
49
44
|
# @raise [DependencyNotFound] if no installed version on your path
|
50
45
|
def assert!
|
51
46
|
version = installed_version
|
52
|
-
raise(DependencyNotFound, "#{@executable} missing.") unless version
|
47
|
+
raise(DependencyNotFound, "'#{@executable}' missing.") unless version
|
53
48
|
|
54
49
|
if @requirement && !@requirement.satisfied_by?(Gem::Version.new(version))
|
55
50
|
raise DependencyVersionMismatch,
|
56
|
-
"expected #{@executable} to be #{@requirement}, got #{version}"
|
51
|
+
"expected '#{@executable}' to be #{@requirement}, got #{version}"
|
57
52
|
end
|
58
53
|
end
|
59
54
|
|
55
|
+
# Finds the executable on your path using {Cliver::Which};
|
56
|
+
# if the executable is present and version requirements are specified,
|
57
|
+
# uses the specified detector to get the current version.
|
60
58
|
# @private
|
61
59
|
# @return [nil] if no version present
|
62
60
|
# @return [String] Gem::Version-parsable string version
|
data/lib/cliver/detector.rb
CHANGED
@@ -6,15 +6,19 @@ module Cliver
|
|
6
6
|
# @see Cliver::Detector::Default for reference implementation
|
7
7
|
module Detector
|
8
8
|
# Forward to default implementation
|
9
|
+
# @see Cliver::Detector::Default
|
10
|
+
# @overload (see Cliver::Detector::Default#initialize)
|
11
|
+
# @param (see Cliver::Detector::Default#initialize)
|
12
|
+
# @raise (see Cliver::Detector::Default#initialize)
|
13
|
+
# @return (see Cliver::Detector::Default#initialize)
|
9
14
|
def self.new(*args, &block)
|
10
15
|
Default.new(*args, &block)
|
11
16
|
end
|
12
17
|
|
13
|
-
# @param
|
18
|
+
# @param executable_path [String] the executable to test
|
14
19
|
# @return [Array<String>]
|
15
|
-
def version_command(
|
16
|
-
raise NotImplementedError
|
17
|
-
super
|
20
|
+
def version_command(executable_path)
|
21
|
+
raise NotImplementedError
|
18
22
|
end
|
19
23
|
|
20
24
|
# @return [Regexp] - the pattern used against the output
|
@@ -25,19 +29,18 @@ module Cliver
|
|
25
29
|
super
|
26
30
|
end
|
27
31
|
|
28
|
-
# @param
|
32
|
+
# @param executable_path [String] - the path to the executable to test
|
29
33
|
# @return [String] - should be Gem::Version-parsable.
|
30
|
-
def detect_version(
|
31
|
-
|
32
|
-
escaped_command_parts = command_parts.map(&Shellwords.method(:escape))
|
33
|
-
output = `#{escaped_command_parts.join(' ')} 2>&1`
|
34
|
+
def detect_version(executable_path)
|
35
|
+
output = `#{version_command(executable_path).shelljoin} 2>&1`
|
34
36
|
ver = output.scan(version_pattern)
|
35
37
|
ver && ver.first
|
36
38
|
end
|
37
39
|
|
38
40
|
# This is the interface that any detector must have.
|
39
|
-
#
|
40
|
-
# @
|
41
|
+
# If not overridden, returns a proc that wraps #detect_version
|
42
|
+
# @see #detect_version
|
43
|
+
# @return [Proc] following method signature of {#detect_version}
|
41
44
|
def to_proc
|
42
45
|
method(:detect_version).to_proc
|
43
46
|
end
|
@@ -8,7 +8,11 @@ module Cliver
|
|
8
8
|
class Detector::Default < Struct.new(:command_arg, :version_pattern)
|
9
9
|
include Detector
|
10
10
|
|
11
|
+
# Default pattern to use when searching {#version_command} output
|
11
12
|
DEFAULT_VERSION_PATTERN = /(?<=version )[0-9][.0-9a-z]+/i.freeze
|
13
|
+
|
14
|
+
# Default command argument to use against the executable to get
|
15
|
+
# version output
|
12
16
|
DEFAULT_COMMAND_ARG = '--version'.freeze
|
13
17
|
|
14
18
|
# Forgiving input, allows either argument if only one supplied.
|
@@ -24,16 +28,25 @@ module Cliver
|
|
24
28
|
super(command_arg, version_pattern)
|
25
29
|
end
|
26
30
|
|
31
|
+
# The pattern to match the version in {#version_command}'s output.
|
32
|
+
# Defaults to {DEFAULT_VERSION_PATTERN}
|
33
|
+
# @overload (see Cliver::Detector#version_pattern)
|
34
|
+
# @return (see Cliver::Detector#version_pattern)
|
27
35
|
def version_pattern
|
28
36
|
super || DEFAULT_VERSION_PATTERN
|
29
37
|
end
|
30
38
|
|
39
|
+
# The argument to pass to the executable to get current version
|
40
|
+
# Defaults to {DEFAULT_COMMAND_ARG}
|
41
|
+
# @return [String]
|
31
42
|
def command_arg
|
32
43
|
super || DEFAULT_COMMAND_ARG
|
33
44
|
end
|
34
45
|
|
35
|
-
|
36
|
-
|
46
|
+
# @overload (see Cliver::Detector#version_command)
|
47
|
+
# @return (see Cliver::Detector#version_command)
|
48
|
+
def version_command(executable_path)
|
49
|
+
[executable_path, command_arg]
|
37
50
|
end
|
38
51
|
end
|
39
52
|
end
|
data/lib/cliver/version.rb
CHANGED
data/lib/cliver/which/posix.rb
CHANGED
data/lib/cliver/which/windows.rb
CHANGED
@@ -6,13 +6,14 @@ module Cliver
|
|
6
6
|
# Windows-specific implementation of Which
|
7
7
|
# Required and mixed into Cliver::Which in windows environments
|
8
8
|
module Windows
|
9
|
+
# Windows-specific implementation of `which`
|
9
10
|
# @param executable [String]
|
10
11
|
# @return [nil,String] - path to found executable
|
11
12
|
def which(executable)
|
12
13
|
# `where` returns newline-separated files found on path, but doesn't
|
13
14
|
# ensure that they are executable as commands.
|
14
15
|
where = `where #{Shellwords.escape executable} 2>&1`
|
15
|
-
where.
|
16
|
+
where.lines.map(&:chomp).find do |found|
|
16
17
|
next if found.empty?
|
17
18
|
File.executable?(found)
|
18
19
|
end
|
data/spec/cliver_spec.rb
CHANGED
@@ -3,4 +3,29 @@ require 'cliver'
|
|
3
3
|
|
4
4
|
describe Cliver do
|
5
5
|
it { should respond_to :assert }
|
6
|
+
|
7
|
+
it { should respond_to :dependency_unmet? }
|
8
|
+
context '#dependency_unmet?' do
|
9
|
+
let(:requirements) { [] }
|
10
|
+
let(:detector) { proc { } }
|
11
|
+
subject { Cliver.dependency_unmet?(executable, *requirements, &detector) }
|
12
|
+
context 'when dependency is met' do
|
13
|
+
let(:executable) { 'ruby' }
|
14
|
+
it { should be_false }
|
15
|
+
end
|
16
|
+
context 'when dependency is present, but wrong version' do
|
17
|
+
let(:executable) { 'ruby' }
|
18
|
+
let(:requirements) { ['~>0.1.0'] }
|
19
|
+
let(:detector) { proc { RUBY_VERSION.sub('p', '.') } }
|
20
|
+
it { should_not be_false }
|
21
|
+
it { should match 'Dependency Version Mismatch:' }
|
22
|
+
it { should match "expected 'ruby' to be #{requirements}" }
|
23
|
+
end
|
24
|
+
context 'when dependency is not present' do
|
25
|
+
let(:executable) { 'ruxxxby' }
|
26
|
+
it { should_not be_false }
|
27
|
+
it { should match 'Dependency Not Found:' }
|
28
|
+
it { should match "'#{executable}' missing" }
|
29
|
+
end
|
30
|
+
end
|
6
31
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cliver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-06-
|
12
|
+
date: 2013-06-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -163,4 +163,4 @@ test_files:
|
|
163
163
|
- spec/cliver/assertion_spec.rb
|
164
164
|
- spec/cliver/detector_spec.rb
|
165
165
|
- spec/cliver_spec.rb
|
166
|
-
has_rdoc:
|
166
|
+
has_rdoc: yard
|