ame 0.1.1 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
data/lib/ame.rb DELETED
@@ -1,26 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- module Ame
4
- AbortAllProcessing = :AmeAbortAllProcessing
5
- AbortProcessing = :AmeAbortProcessing
6
-
7
- Error = Class.new(StandardError)
8
- UnrecognizedMethod = Class.new(Error)
9
- MalformedArgument = Class.new(Error)
10
- MissingArgument = Class.new(Error)
11
- SuperfluousArgument = Class.new(Error)
12
- UnrecognizedOption = Class.new(Error)
13
-
14
- autoload :Argument, 'ame/argument'
15
- autoload :Arguments, 'ame/arguments'
16
- autoload :Class, 'ame/class'
17
- autoload :Help, 'ame/help'
18
- autoload :Method, 'ame/method'
19
- autoload :Methods, 'ame/methods'
20
- autoload :Option, 'ame/option'
21
- autoload :Options, 'ame/options'
22
- autoload :Root, 'ame/root'
23
- autoload :Splat, 'ame/splat'
24
- autoload :Types, 'ame/types'
25
- autoload :Version, 'ame/version'
26
- end
@@ -1,56 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- class Ame::Argument
4
- def initialize(name, description, options = {}, &validate)
5
- @name, @description, @validate = name.to_sym, description, validate || DefaultValidate
6
- @optional = options.fetch(:optional, false)
7
- @type = Ame::Types[[options[:type], options[:default], String].find{ |o| !o.nil? }]
8
- set_default options[:default], options[:type] if options.include? :default
9
- end
10
-
11
- def arity
12
- 1
13
- end
14
-
15
- def process(options, processed, argument)
16
- raise Ame::MissingArgument, 'missing argument: %s' % self if required? and argument.nil?
17
- validate(options, processed, argument)
18
- end
19
-
20
- attr_reader :name, :description, :default
21
-
22
- def optional?
23
- @optional
24
- end
25
-
26
- def required?
27
- not optional?
28
- end
29
-
30
- def to_s
31
- name.to_s.upcase
32
- end
33
-
34
- private
35
-
36
- DefaultValidate = proc{ |options, processed, argument| argument }
37
-
38
- def set_default(value, type)
39
- raise ArgumentError,
40
- 'default value can only be set if optional' unless optional?
41
- raise ArgumentError,
42
- 'default value %s is not of type %s' %
43
- [value, type] unless value.nil? or type.nil? or value.is_a? type
44
- @default = value
45
- end
46
-
47
- def parse(argument)
48
- argument.nil? ? default : @type.parse(argument)
49
- end
50
-
51
- def validate(options, processed, argument)
52
- @validate.call(options, processed, parse(argument))
53
- rescue Ame::MalformedArgument, ArgumentError, TypeError => e
54
- raise Ame::MalformedArgument, '%s: %s' % [self, e]
55
- end
56
- end
@@ -1,65 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- class Ame::Arguments
4
- include Enumerable
5
-
6
- def initialize
7
- @arguments = []
8
- @splat = nil
9
- end
10
-
11
- def argument(name, description, options = {}, &block)
12
- argument = Ame::Argument.new(name, description, options, &block)
13
- raise ArgumentError,
14
- 'argument %s must come before splat argument %s' %
15
- [argument.name, splat.name] if @splat
16
- raise ArgumentError,
17
- 'optional argument %s may not precede required argument %s' %
18
- [first_optional.name, argument.name] if argument.required? and first_optional
19
- @arguments << argument
20
- self
21
- end
22
-
23
- def splat(name = nil, description = nil, options = {}, &validate)
24
- return @splat unless name
25
- splat = Ame::Splat.new(name, description, options, &validate)
26
- raise ArgumentError,
27
- 'splat argument %s already defined: %s' % [@splat.name, splat.name] if @splat
28
- raise ArgumentError,
29
- 'optional argument %s may not precede required splat argument %s' %
30
- [first_optional.name, splat.name] if splat.required? and first_optional
31
- @splat = splat
32
- self
33
- end
34
-
35
- def arity
36
- required = @arguments.select{ |a| a.required? }.size +
37
- (@splat && @splat.required? ? 1 : 0)
38
- @splat || first_optional ? -required - 1 : required
39
- end
40
-
41
- def process(options, arguments)
42
- unprocessed = arguments.dup
43
- reduce([]){ |processed, argument|
44
- processed << argument.process(options, processed,
45
- argument.arity < 0 ? unprocessed : unprocessed.shift)
46
- }.tap{
47
- raise Ame::SuperfluousArgument,
48
- 'superfluous arguments: %s' % unprocessed.join(' ') unless unprocessed.empty?
49
- }
50
- end
51
-
52
- def each
53
- @arguments.each do |argument|
54
- yield argument
55
- end
56
- yield @splat if @splat
57
- self
58
- end
59
-
60
- private
61
-
62
- def first_optional
63
- @arguments.find{ |a| a.optional? }
64
- end
65
- end
@@ -1,117 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- class Ame::Class
4
- class << self
5
- def basename(basename = nil)
6
- @basename = basename if basename
7
- return @basename if defined? @basename
8
- name.split('::').last.scan(/[[:upper:]][[:lower:]]*/).join('-').downcase
9
- end
10
-
11
- def fullname
12
- [].tap{ |names|
13
- klass = self
14
- until klass.nil? or klass.basename.empty?
15
- names << klass.basename
16
- klass = klass.parent
17
- end
18
- }.reverse.join(' ')
19
- end
20
-
21
- def description(description = nil)
22
- return method.description(description) if description
23
- defined?(@description) ? @description : ''
24
- end
25
-
26
- def help_for_dispatch(method, subclass)
27
- parent.help_for_dispatch(method, subclass)
28
- end
29
-
30
- def help_for_method(method)
31
- parent.help_for_method(method)
32
- end
33
-
34
- def methods
35
- @methods ||= Ame::Methods.new
36
- end
37
-
38
- def dispatch(klass, options = {})
39
- klass.parent = self
40
- description klass.description
41
- options_must_precede_arguments
42
- dispatch = method
43
- option :help, 'Display help for this method', :ignore => true do
44
- help_for_dispatch dispatch, klass
45
- throw Ame::AbortAllProcessing
46
- end unless method.options.include? :help
47
- method.arguments.arity.zero? or
48
- raise ArgumentError,
49
- 'arguments may not be defined for a dispatch: %s' % klass
50
- argument :method, 'Method to run', options.include?(:default) ?
51
- {:optional => true, :default => options[:default]} :
52
- {}
53
- splat :arguments, 'Arguments to pass to METHOD', :optional => true
54
- define_method Ame::Method.ruby_name(klass.basename) do |method, arguments|
55
- klass.new.process method, arguments
56
- end
57
- end
58
-
59
- protected
60
-
61
- attr_accessor :parent
62
-
63
- private
64
-
65
- def options_must_precede_arguments
66
- method.options_must_precede_arguments
67
- self
68
- end
69
-
70
- def option(name, description, options = {}, &validate)
71
- method.option name, description, options, &validate
72
- self
73
- end
74
-
75
- def argument(name, description, options = {}, &validate)
76
- method.argument name, description, options, &validate
77
- self
78
- end
79
-
80
- def splat(name, description, options = {}, &validate)
81
- method.splat name, description, options, &validate
82
- self
83
- end
84
-
85
- def method
86
- @method ||= Ame::Method.new(self)
87
- end
88
-
89
- def method_added(name)
90
- if name == :initialize
91
- @description = method.define(name).description
92
- elsif [:process, :call].include? name
93
- method.valid? and
94
- raise NameError, 'method name reserved by Ame: %s' % name
95
- elsif public_method_defined? name
96
- methods << method.define(name)
97
- elsif method.valid?
98
- raise ArgumentError, 'non-public method cannot be used by Ame: %s' % name
99
- end
100
- @method = Ame::Method.new(self)
101
- end
102
- end
103
-
104
- def process(name, arguments = [])
105
- catch Ame::AbortProcessing do
106
- self.class.methods[name].process self, arguments
107
- end
108
- self
109
- end
110
-
111
- def call(name, arguments = nil, options = nil)
112
- catch Ame::AbortProcessing do
113
- self.class.methods[name].call self, arguments, options
114
- end
115
- self
116
- end
117
- end
@@ -1,96 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- class Ame::Help::Console
4
- def initialize(io = $stdout, exit_on_error = true)
5
- @io, @exit_on_error = io, exit_on_error
6
- end
7
-
8
- def for_dispatch(method, subclass)
9
- @io.puts for_method_s(method).tap{ |result|
10
- append_group result, 'Methods', :method, subclass.methods.sort_by{ |m| method(m) }
11
- }
12
- end
13
-
14
- def for_method(method)
15
- @io.puts for_method_s(method)
16
- end
17
-
18
- def version(klass, method)
19
- @io.puts '%s %s' % [method.name, klass.const_get(:Version)]
20
- end
21
-
22
- def for_error(method, error)
23
- @io.puts '%s: %s' % [method, error]
24
- if @exit_on_error
25
- exit 1
26
- else
27
- raise error
28
- end
29
- end
30
-
31
- private
32
-
33
- def for_method_s(method)
34
- ['Usage:'].tap{ |result|
35
- append result, ' ', method.qualified_name
36
- append result, ' ', options_usage(method.options)
37
- append result, ' ', arguments_usage(method.arguments)
38
- result << "\n"
39
- append result, ' ', method.description
40
- append_group result, 'Arguments', :argument, method.arguments
41
- append_group result, 'Options', :option, method.options.sort_by{ |o| (o.short or o.long).to_s }
42
- }.join('')
43
- end
44
-
45
- def append(result, prefix, string)
46
- result << prefix << string unless string.empty?
47
- end
48
-
49
- def append_group(result, heading, display, objects)
50
- longest = objects.map{ |o| send(display, o).length }.max
51
- append result, "\n\n%s:\n" % heading,
52
- objects.map{ |o| ' %-*s %s' % [longest, send(display, o), o.description] }.join("\n")
53
- end
54
-
55
- def options_usage(options)
56
- options.count > 0 ? '[OPTIONS]...' : ''
57
- end
58
-
59
- def arguments_usage(arguments)
60
- arguments.map{ |a|
61
- if a.optional? and a.arity < 0 then '[%s]...'
62
- elsif a.optional? then '[%s]'
63
- elsif a.arity < 0 then '%s...'
64
- else '%s'
65
- end % a
66
- }.join(' ')
67
- end
68
-
69
- def argument(argument)
70
- result = argument.to_s
71
- result << '=%s' % argument.default if argument.default
72
- result = '[%s]' % result if argument.optional?
73
- result << '...' if argument.arity < 0
74
- result
75
- end
76
-
77
- def option(option)
78
- if not option.long and option.argument_name.empty?
79
- '-%s' % option.short
80
- elsif not option.long
81
- '-%s=%s' % [option.short, option.argument_name.upcase]
82
- elsif option.short and option.argument_name.empty?
83
- '-%s, --%s' % [option.short, option.long]
84
- elsif option.short
85
- '-%s, --%s=%s' % [option.short, option.long, option.argument_name.upcase]
86
- elsif option.argument_name.empty?
87
- ' --%s' % option.long
88
- else
89
- ' --%s=%s' % [option.long, option.argument_name.upcase]
90
- end
91
- end
92
-
93
- def method(method)
94
- method.name.to_s
95
- end
96
- end
@@ -1,94 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- class Ame::Method
4
- class << self
5
- def ruby_name(name)
6
- name.to_s.gsub('-', '_').to_sym
7
- end
8
-
9
- def name(name)
10
- name.to_s.gsub('_', '-').to_sym
11
- end
12
- end
13
-
14
- def initialize(klass)
15
- @class = klass
16
- @description = nil
17
- end
18
-
19
- def description(description = nil)
20
- return @description unless description
21
- @description = description
22
- self
23
- end
24
-
25
- def options_must_precede_arguments
26
- self.options.options_must_precede_arguments
27
- self
28
- end
29
-
30
- def option(name, description, options = {}, &validate)
31
- self.options.option name, description, options, &validate
32
- self
33
- end
34
-
35
- def argument(name, description, options = {}, &validate)
36
- arguments.argument name, description, options, &validate
37
- self
38
- end
39
-
40
- def splat(name, description, options = {}, &validate)
41
- arguments.splat name, description, options, &validate
42
- self
43
- end
44
-
45
- def arity
46
- arguments.arity
47
- end
48
-
49
- def define(name)
50
- self.name = name
51
- option :help, 'Display help for this method', :ignore => true do
52
- @class.help_for_method self
53
- throw Ame::AbortAllProcessing
54
- end unless options.include? :help
55
- self
56
- end
57
-
58
- def valid?
59
- not description.nil?
60
- end
61
-
62
- def process(instance, arguments)
63
- options, remainder = self.options.process(arguments)
64
- call(instance, self.arguments.process(options, remainder), options)
65
- end
66
-
67
- def call(instance, arguments = nil, options = nil)
68
- options, _ = self.options.process([]) unless options
69
- arguments ||= self.arguments.process(options, [])
70
- instance.send ruby_name, *(arguments + (options.empty? ? [] : [options]))
71
- self
72
- end
73
-
74
- attr_reader :name, :ruby_name
75
-
76
- def qualified_name
77
- [@class.fullname, name.to_s].reject{ |n| n.empty? }.join(' ')
78
- end
79
-
80
- def options
81
- @options ||= Ame::Options.new
82
- end
83
-
84
- def arguments
85
- @arguments ||= Ame::Arguments.new
86
- end
87
-
88
- private
89
-
90
- def name=(name)
91
- @ruby_name = name
92
- @name = self.class.name(name)
93
- end
94
- end