ame 0.1.1 → 1.0.1

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.
Files changed (90) hide show
  1. checksums.yaml +7 -0
  2. data/README +541 -3
  3. data/Rakefile +15 -6
  4. data/lib/ame-1.0.rb +31 -0
  5. data/lib/ame-1.0/argument.rb +63 -0
  6. data/lib/ame-1.0/arguments.rb +44 -0
  7. data/lib/ame-1.0/arguments/complete.rb +37 -0
  8. data/lib/ame-1.0/arguments/optional.rb +34 -0
  9. data/lib/ame-1.0/arguments/undefined.rb +71 -0
  10. data/lib/ame-1.0/class.rb +436 -0
  11. data/lib/ame-1.0/flag.rb +101 -0
  12. data/lib/{ame → ame-1.0}/help.rb +1 -1
  13. data/lib/ame-1.0/help/delegate.rb +19 -0
  14. data/lib/ame-1.0/help/terminal.rb +132 -0
  15. data/lib/ame-1.0/method.rb +75 -0
  16. data/lib/ame-1.0/method/undefined.rb +184 -0
  17. data/lib/ame-1.0/methods.rb +40 -0
  18. data/lib/ame-1.0/multioption.rb +36 -0
  19. data/lib/ame-1.0/option.rb +37 -0
  20. data/lib/ame-1.0/optional.rb +31 -0
  21. data/lib/ame-1.0/options.rb +68 -0
  22. data/lib/ame-1.0/options/undefined.rb +114 -0
  23. data/lib/ame-1.0/root.rb +174 -0
  24. data/lib/ame-1.0/splat.rb +16 -0
  25. data/lib/ame-1.0/splus.rb +22 -0
  26. data/lib/ame-1.0/switch.rb +39 -0
  27. data/lib/ame-1.0/types.rb +60 -0
  28. data/lib/ame-1.0/types/boolean.rb +13 -0
  29. data/lib/ame-1.0/types/enumeration.rb +40 -0
  30. data/lib/ame-1.0/types/float.rb +11 -0
  31. data/lib/{ame → ame-1.0}/types/integer.rb +3 -3
  32. data/lib/{ame → ame-1.0}/types/string.rb +2 -2
  33. data/lib/ame-1.0/types/symbol.rb +9 -0
  34. data/lib/ame-1.0/version.rb +62 -0
  35. data/test/unit/ame-1.0.rb +4 -0
  36. data/test/unit/ame-1.0/argument.rb +46 -0
  37. data/test/unit/ame-1.0/arguments.rb +63 -0
  38. data/test/unit/ame-1.0/arguments/complete.rb +4 -0
  39. data/test/unit/ame-1.0/arguments/optional.rb +4 -0
  40. data/test/unit/ame-1.0/arguments/undefined.rb +63 -0
  41. data/test/unit/ame-1.0/class.rb +4 -0
  42. data/test/unit/ame-1.0/flag.rb +31 -0
  43. data/test/unit/ame-1.0/help.rb +4 -0
  44. data/test/unit/ame-1.0/help/delegate.rb +4 -0
  45. data/test/unit/{ame/help/console.rb → ame-1.0/help/terminal.rb} +34 -23
  46. data/test/unit/ame-1.0/method.rb +4 -0
  47. data/test/unit/ame-1.0/method/undefined.rb +33 -0
  48. data/test/unit/ame-1.0/methods.rb +9 -0
  49. data/test/unit/ame-1.0/multioption.rb +4 -0
  50. data/test/unit/ame-1.0/option.rb +11 -0
  51. data/test/unit/ame-1.0/optional.rb +9 -0
  52. data/test/unit/ame-1.0/options.rb +149 -0
  53. data/test/unit/ame-1.0/options/undefined.rb +33 -0
  54. data/test/unit/ame-1.0/root.rb +4 -0
  55. data/test/unit/ame-1.0/splat.rb +9 -0
  56. data/test/unit/ame-1.0/splus.rb +4 -0
  57. data/test/unit/ame-1.0/switch.rb +15 -0
  58. data/test/unit/ame-1.0/types.rb +4 -0
  59. data/test/{ame → unit/ame-1.0}/types/boolean.rb +0 -0
  60. data/test/unit/ame-1.0/types/enumeration.rb +4 -0
  61. data/test/unit/ame-1.0/types/float.rb +7 -0
  62. data/test/{ame → unit/ame-1.0}/types/integer.rb +0 -0
  63. data/test/{ame → unit/ame-1.0}/types/string.rb +0 -0
  64. data/test/unit/ame-1.0/types/symbol.rb +5 -0
  65. data/test/unit/ame-1.0/version.rb +4 -0
  66. metadata +690 -60
  67. data/lib/ame.rb +0 -26
  68. data/lib/ame/argument.rb +0 -56
  69. data/lib/ame/arguments.rb +0 -65
  70. data/lib/ame/class.rb +0 -117
  71. data/lib/ame/help/console.rb +0 -96
  72. data/lib/ame/method.rb +0 -94
  73. data/lib/ame/methods.rb +0 -30
  74. data/lib/ame/option.rb +0 -50
  75. data/lib/ame/options.rb +0 -102
  76. data/lib/ame/root.rb +0 -57
  77. data/lib/ame/splat.rb +0 -12
  78. data/lib/ame/types.rb +0 -29
  79. data/lib/ame/types/array.rb +0 -16
  80. data/lib/ame/types/boolean.rb +0 -16
  81. data/lib/ame/version.rb +0 -5
  82. data/test/ame/types/array.rb +0 -13
  83. data/test/unit/ame/argument.rb +0 -66
  84. data/test/unit/ame/arguments.rb +0 -106
  85. data/test/unit/ame/method.rb +0 -40
  86. data/test/unit/ame/methods.rb +0 -10
  87. data/test/unit/ame/option.rb +0 -75
  88. data/test/unit/ame/options.rb +0 -136
  89. data/test/unit/ame/root.rb +0 -15
  90. data/test/unit/ame/splat.rb +0 -11
@@ -0,0 +1,16 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # Represents a splat argument to a {Method}, which works just like a {Splus},
4
+ # except that it won’t fail if there are no more arguments left.
5
+ # @api developer
6
+ class Ame::Splat < Ame::Splus
7
+ # Processes each argument in ARGUMENTS via {Argument#process}.
8
+ # @api internal
9
+ # @param (see Argument#process)
10
+ # @raise [Ame::MalformedArgument] If the receiver couldn’t be parsed or
11
+ # validated
12
+ # @return [Array<Object>]
13
+ def process(options, processed, arguments)
14
+ arguments.empty? ? [] : super
15
+ end
16
+ end
@@ -0,0 +1,22 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # Represents a splus argument to a {Method}, which works just like a normal
4
+ # {Argument}, except that it’ll process all remaining arguments.
5
+ # @api developer
6
+ class Ame::Splus < Ame::Argument
7
+ # Processes each argument in ARGUMENTS via {Argument#process}.
8
+ # @api internal
9
+ # @param (see Argument#process)
10
+ # @raise [Ame::MissingArgument] If ARGUMENTS#empty?
11
+ # @raise [Ame::MalformedArgument] If the receiver couldn’t be parsed or
12
+ # validated
13
+ # @return [Array<Object>]
14
+ def process(options, processed, arguments)
15
+ super options, processed, arguments if arguments.empty?
16
+ [].tap{ |r|
17
+ until arguments.empty?
18
+ r << super(options, processed, arguments)
19
+ end
20
+ }
21
+ end
22
+ end
@@ -0,0 +1,39 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # Represents an option to a {Method} that takes an optional argument. If an
4
+ # explicit (‘=’-separated) argument is given, it’ll be used, otherwise a
5
+ # default value, which differs from the default value used if the option isn’t
6
+ # given at all, will be used.
7
+ # @api developer
8
+ class Ame::Switch < Ame::Flag
9
+ # @api internal
10
+ # @param (see Flag#initialize)
11
+ # @param [String] argument
12
+ # @param [Object] default
13
+ # @param [Object] argument_default
14
+ # @yield (see Flag#initialize)
15
+ # @yieldparam [Hash<String, Object>] options
16
+ # @yieldparam [Object] value
17
+ # @raise (see Flag#initialize)
18
+ # @raise [ArgumentError] If the type of ARGUMENT_DEFAULT or, if
19
+ # ARGUMENT_DEFAULT is nil, DEFAULT isn’t one that Ame knows how to parse
20
+ def initialize(short, long, argument, default, argument_default, description, &validate)
21
+ @argument = argument.upcase
22
+ @type = Ame::Types[[argument_default, default, String].reject(&:nil?).first]
23
+ @argument_default = @type.respond_to?(:default) ? @type.default : argument_default
24
+ super short, long, default, description, &validate
25
+ end
26
+
27
+ # @return [String] The name of the argument to the receiver
28
+ attr_reader :argument
29
+
30
+ private
31
+
32
+ # @api internal
33
+ # @param (see Flag#parse)
34
+ # @return [Object] The parsed value of EXPLICIT, if non-nil, the default
35
+ # argument value otherwise
36
+ def parse(arguments, explicit)
37
+ explicit ? @type.parse(explicit) : @argument_default
38
+ end
39
+ end
@@ -0,0 +1,60 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # Types registered with Ame for parsing command-line arguments into Ruby
4
+ # values. By default, Ruby classes TrueClass, FalseClass, Float, Integer,
5
+ # String, and Symbol are registered, as well as an {Enumeration} type for
6
+ # limiting a Symbol to one of a fixed set.
7
+ module Ame::Types
8
+ @types = {}
9
+
10
+ class << self
11
+ # Registers TYPE for parsing command-line arguments for Ruby values whose
12
+ # class is any of CLASSES. The TYPE should respond to #parse(String),
13
+ # which should convert its String argument into a Ruby value, and may
14
+ # optionally respond to #default, which should return the default value of
15
+ # the TYPE, if any.
16
+ # @param [#parse, #default] type
17
+ # @param [::Class, …] classes
18
+ # @return [self]
19
+ # @example Registering a New Type
20
+ # require 'pathname'
21
+ #
22
+ # module My::Pathname
23
+ # Ame::Types.register self, Pathname
24
+ #
25
+ # def parse(argument)
26
+ # Pathname(argument)
27
+ # end
28
+ # end
29
+ # @example Using a New Type as a Type
30
+ # class Rm < Ame::Root
31
+ # …
32
+ # splus 'FILE', My::Pathname, 'File to remove'
33
+ # def rm(pathnames)
34
+ # pathnames.each do |e| e.rmtree end
35
+ # end
36
+ # end
37
+ # @example Using a New Types as a Default
38
+ # class My < Ame::Root
39
+ # optional 'CONFIG', Pathname('/etc/my/config'), 'Configuration file to use'
40
+ def register(type, *classes)
41
+ classes.each do |c|
42
+ @types[c] = type
43
+ end
44
+ self
45
+ end
46
+
47
+ # @api developer
48
+ # @return [Object] The type registered to parse arguments into values of
49
+ # CLASS_OR_VALUE or of the class of CLASS_OR_VALUE, alternatively using
50
+ # CLASS_OR_VALUE itself if it responds to #parse
51
+ # @raise [ArgumentError] If a type that handles CLASS_OR_VALUE hasn’t been
52
+ # registered
53
+ def [](class_or_value)
54
+ type = @types[class_or_value] and return type
55
+ pair = @types.find{ |c, t| class_or_value.is_a? c } and return pair.last
56
+ class_or_value.respond_to? :parse and return class_or_value
57
+ raise ArgumentError, 'unknown type: %p' % [class_or_value]
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,13 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Ame::Types::Boolean
4
+ Ame::Types.register self, TrueClass, FalseClass
5
+
6
+ def self.parse(argument)
7
+ case argument
8
+ when 'true', 'yes', 'on' then true
9
+ when 'false', 'no', 'off' then false
10
+ else raise Ame::MalformedArgument, 'not a boolean: %s' % argument
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,40 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # Enumeration type for limiting a Symbol argument to one in a fixed set. It
4
+ # also has a {#default}, which will be the first symbol passed to its
5
+ # constructor.
6
+ # @example Using an Enumeration
7
+ # class Git::CLI::Git::FormatPatch < Ame::Class
8
+ # switch '', 'thread', 'STYLE', nil,
9
+ # Ame::Types::Enumeration[:shallow, :deep],
10
+ # 'Controls addition of In-Reply-To and References headers'
11
+ class Ame::Types::Enumeration
12
+ class << self
13
+ # Alias for .new.
14
+ alias [] new
15
+ end
16
+
17
+ # Creates an Enumeration of valid Symbols FIRST, SECOND, and REST for an
18
+ # argument and sets {#default} to FIRST.
19
+ # @param [#to_sym] first
20
+ # @param [#to_sym] second
21
+ # @param [#to_sym, …] rest
22
+ def initialize(first, second, *rest)
23
+ @default = first
24
+ @names = ([first, second] + rest).map(&:to_sym)
25
+ end
26
+
27
+ # @api internal
28
+ # @param [String] argument
29
+ # @return [Symbol] The result of ARGUMENT#to_sym
30
+ # @raise [MalformedArgument] If ARGUMENT#to_sym isn’t included among the
31
+ # valid Symbols
32
+ def parse(argument)
33
+ @names.include?(s = argument.to_sym) ? s :
34
+ raise(Ame::MalformedArgument, 'must be one of %s, not %s' %
35
+ [@names.join(', '), argument])
36
+ end
37
+
38
+ # @return [Symbol] The Symbol to use if no argument has been given
39
+ attr_reader :default
40
+ end
@@ -0,0 +1,11 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Ame::Types::Float
4
+ Ame::Types.register self, Float
5
+
6
+ def self.parse(argument)
7
+ Float(argument)
8
+ rescue ArgumentError
9
+ raise Ame::MalformedArgument, 'not a float: %s' % argument
10
+ end
11
+ end
@@ -3,9 +3,9 @@
3
3
  module Ame::Types::Integer
4
4
  Ame::Types.register self, Integer
5
5
 
6
- def self.parse(value)
7
- Integer(value)
6
+ def self.parse(argument)
7
+ Integer(argument)
8
8
  rescue ArgumentError
9
- raise Ame::MalformedArgument, 'not an integer: %s' % value
9
+ raise Ame::MalformedArgument, 'not an integer: %s' % argument
10
10
  end
11
11
  end
@@ -3,7 +3,7 @@
3
3
  module Ame::Types::String
4
4
  Ame::Types.register self, String
5
5
 
6
- def self.parse(value)
7
- value
6
+ def self.parse(argument)
7
+ argument
8
8
  end
9
9
  end
@@ -0,0 +1,9 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Ame::Types::Symbol
4
+ Ame::Types.register self, Symbol
5
+
6
+ def self.parse(argument)
7
+ argument.to_sym
8
+ end
9
+ end
@@ -0,0 +1,62 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'inventory-1.0'
4
+
5
+ module Ame
6
+ Version = Inventory.new(1, 0, 1){
7
+ authors{
8
+ author 'Nikolai Weibull', 'now@disu.se'
9
+ }
10
+
11
+ homepage 'http://disu.se/software/ame-1.0/'
12
+
13
+ licenses{
14
+ license 'LGPLv3+',
15
+ 'GNU Lesser General Public License, version 3 or later',
16
+ 'http://www.gnu.org/licenses/'
17
+ }
18
+
19
+ def dependencies
20
+ super + Inventory::Dependencies.new{
21
+ development 'inventory-rake', 1, 6, 0
22
+ development 'inventory-rake-tasks-yard', 1, 4, 0
23
+ development 'lookout', 3, 0, 0
24
+ development 'lookout-rake', 3, 1, 0
25
+ development 'yard', 0, 8, 0
26
+ development 'yard-heuristics', 1, 2, 0
27
+ }
28
+ end
29
+
30
+ def package_libs
31
+ %w[argument.rb
32
+ arguments.rb
33
+ arguments/undefined.rb
34
+ arguments/optional.rb
35
+ arguments/complete.rb
36
+ class.rb
37
+ flag.rb
38
+ help.rb
39
+ help/terminal.rb
40
+ help/delegate.rb
41
+ method.rb
42
+ method/undefined.rb
43
+ methods.rb
44
+ switch.rb
45
+ option.rb
46
+ multioption.rb
47
+ optional.rb
48
+ options.rb
49
+ options/undefined.rb
50
+ root.rb
51
+ splus.rb
52
+ splat.rb
53
+ types.rb
54
+ types/boolean.rb
55
+ types/enumeration.rb
56
+ types/float.rb
57
+ types/integer.rb
58
+ types/string.rb
59
+ types/symbol.rb]
60
+ end
61
+ }
62
+ end
@@ -0,0 +1,4 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ Expectations do
4
+ end
@@ -0,0 +1,46 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ Expectations do
4
+ expect 'a' do Ame::Argument.new('a', String, 'd').name end
5
+
6
+ expect 'd' do Ame::Argument.new('a', String, 'd').description end
7
+
8
+ expect 'A' do Ame::Argument.new('a', String, 'd').to_s end
9
+
10
+ expect Ame::MissingArgument do Ame::Argument.new('a', String, 'd').process({}, [], []) end
11
+ expect 'string' do Ame::Argument.new('a', String, 'd').process({}, [], ['string']) end
12
+
13
+ expect 1 do Ame::Argument.new('a', Integer, 'd').process({}, [], ['1']) end
14
+ expect Ame::MalformedArgument.new('A: not an integer: junk') do
15
+ Ame::Argument.new('a', Integer, 'd').process({}, [], ['junk'])
16
+ end
17
+
18
+ expect TrueClass do Ame::Argument.new('a', TrueClass, 'd').process({}, [], ['true']) end
19
+ expect Ame::MalformedArgument.new('A: not a boolean: junk') do
20
+ Ame::Argument.new('a', TrueClass, 'd').process({}, [], ['junk'])
21
+ end
22
+
23
+ expect FalseClass do Ame::Argument.new(:a, FalseClass, 'd').process({}, [], ['false']) end
24
+ expect Ame::MalformedArgument.new('A: not a boolean: junk') do
25
+ Ame::Argument.new('a', FalseClass, 'd').process({}, [], ['junk'])
26
+ end
27
+
28
+ expect :a => 1 do
29
+ options = nil
30
+ Ame::Argument.new('a', Integer, 'd'){ |o, p, a| options = o }.process({:a => 1}, [1], ['2'])
31
+ options
32
+ end
33
+ expect [1] do
34
+ processed = nil
35
+ Ame::Argument.new('a', Integer, 'd'){ |o, p, a| processed = p }.process({:a => 1}, [1], ['2'])
36
+ processed
37
+ end
38
+ expect 2 do
39
+ argument = nil
40
+ Ame::Argument.new('a', Integer, 'd'){ |o, p, a| argument = a }.process({:a => 1}, [1], ['2'])
41
+ argument
42
+ end
43
+ expect 3 do
44
+ Ame::Argument.new('a', Integer, 'd'){ |o, p, a| 3 }.process({:a => 1}, [1], ['2'])
45
+ end
46
+ end
@@ -0,0 +1,63 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ Expectations do
4
+ expect Enumerable do Ame::Arguments::Undefined.new.define end
5
+
6
+ expect Ame::MissingArgument do
7
+ Ame::Arguments::Undefined.new.
8
+ argument('a', String, 'd').
9
+ define.
10
+ process({}, [])
11
+ end
12
+
13
+ expect [] do
14
+ Ame::Arguments::Undefined.new.
15
+ define.
16
+ process({}, [])
17
+ end
18
+
19
+ expect [1] do
20
+ Ame::Arguments::Undefined.new.
21
+ argument('a', Integer, 'd').
22
+ define.
23
+ process({}, %w[1])
24
+ end
25
+
26
+ expect [1, TrueClass] do
27
+ Ame::Arguments::Undefined.new.
28
+ argument('a', Integer, 'd').
29
+ argument('b', FalseClass, 'd').
30
+ define.
31
+ process({}, %w[1 true])
32
+ end
33
+
34
+ expect Ame::MissingArgument do
35
+ Ame::Arguments::Undefined.new.
36
+ argument('a', 'd', :type => Integer).
37
+ splus('b', String, 'd').
38
+ define.
39
+ process({}, %w[1])
40
+ end
41
+
42
+ expect [1, []] do
43
+ Ame::Arguments::Undefined.new.
44
+ argument('a', Integer, 'd').
45
+ splat('b', String, 'd').
46
+ define.
47
+ process({}, %w[1])
48
+ end
49
+
50
+ expect [1, [2, 3]] do
51
+ Ame::Arguments::Undefined.new.
52
+ argument('a', Integer, 'd').
53
+ splus('b', Integer, 'd').
54
+ define.
55
+ process({}, %w[1 2 3])
56
+ end
57
+
58
+ expect Ame::SuperfluousArgument do
59
+ Ame::Arguments::Undefined.new.
60
+ define.
61
+ process({}, %w[1])
62
+ end
63
+ end
@@ -0,0 +1,4 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ Expectations do
4
+ end
@@ -0,0 +1,4 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ Expectations do
4
+ end
@@ -0,0 +1,63 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ Expectations do
4
+ expect ArgumentError.new("argument 'b', … may not follow optional 'a', …") do
5
+ Ame::Arguments::Undefined.new.
6
+ optional('a', nil, 'd').
7
+ argument('b', String, 'd')
8
+ end
9
+
10
+ expect ArgumentError.new("splus 'b', … may not follow optional 'a', …") do
11
+ Ame::Arguments::Undefined.new.
12
+ optional('a', nil, 'd').
13
+ splus('b', String, 'd')
14
+ end
15
+
16
+ expect ArgumentError.new("argument 'b', … may not follow splat 'a', …") do
17
+ Ame::Arguments::Undefined.new.
18
+ splat('a', String, 'd').
19
+ argument('b', String, 'd')
20
+ end
21
+
22
+ expect ArgumentError.new("optional 'b', … may not follow splat 'a', …") do
23
+ Ame::Arguments::Undefined.new.
24
+ splat('a', String, 'd').
25
+ optional('b', String, 'd')
26
+ end
27
+
28
+ expect ArgumentError.new("splat 'b', … may not follow splat 'a', …") do
29
+ Ame::Arguments::Undefined.new.
30
+ splat('a', String, 'd').
31
+ splat('b', String, 'd')
32
+ end
33
+
34
+ expect ArgumentError.new("splus 'b', … may not follow splat 'a', …") do
35
+ Ame::Arguments::Undefined.new.
36
+ splat('a', String, 'd').
37
+ splus('b', String, 'd')
38
+ end
39
+
40
+ expect ArgumentError.new("argument 'b', … may not follow splus 'a', …") do
41
+ Ame::Arguments::Undefined.new.
42
+ splus('a', String, 'd').
43
+ argument('b', String, 'd')
44
+ end
45
+
46
+ expect ArgumentError.new("optional 'b', … may not follow splus 'a', …") do
47
+ Ame::Arguments::Undefined.new.
48
+ splus('a', String, 'd').
49
+ optional('b', String, 'd')
50
+ end
51
+
52
+ expect ArgumentError.new("splat 'b', … may not follow splus 'a', …") do
53
+ Ame::Arguments::Undefined.new.
54
+ splus('a', String, 'd').
55
+ splat('b', String, 'd')
56
+ end
57
+
58
+ expect ArgumentError.new("splus 'b', … may not follow splus 'a', …") do
59
+ Ame::Arguments::Undefined.new.
60
+ splus('a', String, 'd').
61
+ splus('b', String, 'd')
62
+ end
63
+ end