cliqr 1.2.0 → 2.0.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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +95 -0
  3. data/README.md +9 -71
  4. data/examples/numbers +1 -2
  5. data/examples/vagrant +0 -3
  6. data/lib/cliqr.rb +52 -11
  7. data/lib/cliqr/argument_validation/argument_type_validator.rb +2 -2
  8. data/lib/cliqr/argument_validation/validator.rb +3 -3
  9. data/lib/cliqr/{cli → command}/argument_operator.rb +2 -2
  10. data/lib/cliqr/{cli → command}/argument_operator_context.rb +1 -1
  11. data/lib/cliqr/{cli/command.rb → command/base_command.rb} +2 -2
  12. data/lib/cliqr/command/color.rb +174 -0
  13. data/lib/cliqr/{cli → command}/command_context.rb +68 -20
  14. data/lib/cliqr/command/shell_banner_builder.rb +17 -0
  15. data/lib/cliqr/command/shell_command.rb +125 -0
  16. data/lib/cliqr/command/shell_prompt_builder.rb +26 -0
  17. data/lib/cliqr/config/action.rb +226 -0
  18. data/lib/cliqr/config/base.rb +84 -0
  19. data/lib/cliqr/config/command.rb +137 -0
  20. data/lib/cliqr/config/dsl.rb +81 -0
  21. data/lib/cliqr/config/event.rb +43 -0
  22. data/lib/cliqr/config/event_based.rb +78 -0
  23. data/lib/cliqr/config/named.rb +55 -0
  24. data/lib/cliqr/config/option.rb +95 -0
  25. data/lib/cliqr/config/option_based.rb +130 -0
  26. data/lib/cliqr/config/shell.rb +87 -0
  27. data/lib/cliqr/config/validation/validation_set.rb +66 -0
  28. data/lib/cliqr/config/validation/validator_factory.rb +403 -0
  29. data/lib/cliqr/config/validation/verifiable.rb +91 -0
  30. data/lib/cliqr/error.rb +20 -4
  31. data/lib/cliqr/events/event.rb +56 -0
  32. data/lib/cliqr/events/event_context.rb +31 -0
  33. data/lib/cliqr/events/handler.rb +32 -0
  34. data/lib/cliqr/events/invoker.rb +70 -0
  35. data/lib/cliqr/{cli → executor}/command_runner_factory.rb +3 -3
  36. data/lib/cliqr/{cli → executor}/router.rb +4 -4
  37. data/lib/cliqr/{cli/executor.rb → executor/runner.rb} +25 -10
  38. data/lib/cliqr/interface.rb +98 -0
  39. data/lib/cliqr/parser/token_factory.rb +1 -1
  40. data/lib/cliqr/usage/command_usage_context.rb +94 -0
  41. data/lib/cliqr/usage/option_usage_context.rb +86 -0
  42. data/lib/cliqr/usage/templates/partial/action_list.erb +10 -0
  43. data/lib/cliqr/usage/templates/partial/command_name.erb +3 -0
  44. data/lib/cliqr/usage/templates/partial/option_list.erb +18 -0
  45. data/lib/cliqr/usage/templates/partial/usage_info.erb +5 -0
  46. data/lib/cliqr/usage/templates/usage/cli.erb +4 -0
  47. data/lib/cliqr/usage/templates/usage/shell.erb +2 -0
  48. data/lib/cliqr/usage/usage_builder.rb +59 -0
  49. data/lib/cliqr/util.rb +81 -34
  50. data/lib/cliqr/version.rb +1 -1
  51. data/spec/config/action_config_validator_spec.rb +127 -5
  52. data/spec/config/config_finalize_spec.rb +3 -3
  53. data/spec/config/config_validator_spec.rb +120 -17
  54. data/spec/config/option_config_validator_spec.rb +1 -1
  55. data/spec/dsl/interface_spec.rb +2 -2
  56. data/spec/dsl/usage_spec.rb +461 -465
  57. data/spec/executor/action_executor_spec.rb +1 -1
  58. data/spec/executor/color_executor_spec.rb +125 -0
  59. data/spec/executor/command_runner_spec.rb +6 -8
  60. data/spec/executor/event_executor_spec.rb +365 -0
  61. data/spec/executor/executor_spec.rb +49 -11
  62. data/spec/executor/help_executor_spec.rb +107 -103
  63. data/spec/fixtures/action_reader_command.rb +1 -1
  64. data/spec/fixtures/test_arg_printer_event_handler.rb +9 -0
  65. data/spec/fixtures/test_color_shell_prompt.rb +13 -0
  66. data/spec/fixtures/test_empty_event_handler.rb +5 -0
  67. data/spec/fixtures/test_invoker_event_handler.rb +9 -0
  68. data/spec/fixtures/test_shell_banner.rb +8 -0
  69. data/spec/fixtures/test_shell_prompt.rb +13 -0
  70. data/spec/shell/shell_executor_spec.rb +700 -0
  71. data/spec/validation/validation_spec.rb +2 -2
  72. metadata +65 -27
  73. data/lib/cliqr/cli/config.rb +0 -554
  74. data/lib/cliqr/cli/interface.rb +0 -107
  75. data/lib/cliqr/cli/shell_command.rb +0 -69
  76. data/lib/cliqr/cli/usage_builder.rb +0 -185
  77. data/lib/cliqr/config_validation/validation_set.rb +0 -48
  78. data/lib/cliqr/config_validation/validator_factory.rb +0 -319
  79. data/lib/cliqr/config_validation/verifiable.rb +0 -89
  80. data/lib/cliqr/dsl.rb +0 -59
  81. data/spec/executor/shell_executor_spec.rb +0 -233
  82. data/templates/usage.erb +0 -39
@@ -0,0 +1,84 @@
1
+ # encoding: utf-8
2
+
3
+ require 'cliqr/config/dsl'
4
+ require 'cliqr/config/validation/verifiable'
5
+
6
+ module Cliqr
7
+ # A extension for CLI module to group all config classes
8
+ #
9
+ # @api private
10
+ module Config
11
+ # A value to initialize configuration attributes with
12
+ UNSET = Object.new
13
+
14
+ # Configuration option to enable arguments for a command (default)
15
+ ENABLE_CONFIG = :enable
16
+
17
+ # Configuration option to disable arguments for a command
18
+ DISABLE_CONFIG = :disable
19
+
20
+ # Option type for regular options
21
+ ANY_ARGUMENT_TYPE = :any
22
+
23
+ # Option type for numeric arguments
24
+ NUMERIC_ARGUMENT_TYPE = :numeric
25
+
26
+ # Option type for boolean arguments
27
+ BOOLEAN_ARGUMENT_TYPE = :boolean
28
+
29
+ # Default values based on argument type
30
+ ARGUMENT_DEFAULTS = {
31
+ NUMERIC_ARGUMENT_TYPE => 0,
32
+ BOOLEAN_ARGUMENT_TYPE => false,
33
+ ANY_ARGUMENT_TYPE => nil
34
+ }
35
+
36
+ # Get the passed param value if current attribute is unset
37
+ #
38
+ # @return [Object]
39
+ def self.get_if_unset(attribute_value, default_value)
40
+ return attribute_value unless attribute_value == UNSET
41
+ if default_value.is_a?(Proc)
42
+ default_value.call
43
+ else
44
+ default_value
45
+ end
46
+ end
47
+
48
+ # The base configuration setting to build a cli application with its own dsl
49
+ class Base
50
+ include Cliqr::Config::DSL
51
+ include Cliqr::Config::Validation
52
+
53
+ # Set value for an attribute
54
+ #
55
+ # @param [Symbol] name Name of the config parameter
56
+ # @param [Object] value Value for the config parameter
57
+ # @param [Proc] block Function which populates configuration for a sub-attribute
58
+ #
59
+ # @return [Object] new attribute's value
60
+ def set_config(name, value, *_args, &block)
61
+ value = block if block_given?
62
+ handle_config(name, value)
63
+ end
64
+
65
+ # Skip validation if this is <tt>true</tt>
66
+ def skip_validation?
67
+ false
68
+ end
69
+
70
+ private
71
+
72
+ # Set value for an attribute by evaluating a block
73
+ #
74
+ # @param [Symbol] name Name of the config option
75
+ # @param [Object] value Value for the config option
76
+ #
77
+ # @return [Object]
78
+ def handle_config(name, value)
79
+ public_send("#{name}=", value)
80
+ value
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,137 @@
1
+ # encoding: utf-8
2
+
3
+ require 'cliqr/command/base_command'
4
+ require 'cliqr/config/action'
5
+ require 'cliqr/config/shell'
6
+
7
+ module Cliqr
8
+ module Config
9
+ # Configuration setting for a command
10
+ #
11
+ # @api private
12
+ class Command < Cliqr::Config::Action
13
+ # Configuration for the shell for this command
14
+ #
15
+ # @return [Cliqr::Command::ShellConfig]
16
+ attr_accessor :shell
17
+ validates :shell,
18
+ child: true
19
+
20
+ # Version tag for this configuration
21
+ #
22
+ # @return [Stirng]
23
+ attr_accessor :version
24
+
25
+ # Enable or disable colors in a command handler (default enabled)
26
+ #
27
+ # @return [Symbol]
28
+ attr_accessor :color
29
+ validates :color,
30
+ inclusion: [Cliqr::Config::ENABLE_CONFIG, Cliqr::Config::DISABLE_CONFIG]
31
+
32
+ # New config instance with all attributes set as UNSET
33
+ def initialize
34
+ super
35
+
36
+ @shell = UNSET
37
+ @version = UNSET
38
+ @color = UNSET
39
+ end
40
+
41
+ # Finalize config by adding default values for unset values
42
+ #
43
+ # @return [Cliqr::Config::Command]
44
+ def finalize
45
+ super
46
+
47
+ @color = Config.get_if_unset(@color, Cliqr::Config::ENABLE_CONFIG)
48
+ @shell = Config.get_if_unset(@shell, proc { Cliqr::Util.build_shell_config(self) })
49
+ @version = Config.get_if_unset(@version, nil)
50
+
51
+ # disable colors in shell if colors are disabled here
52
+ @shell.disable_color unless color?
53
+
54
+ self
55
+ end
56
+
57
+ # Set value for a config option
58
+ #
59
+ # @param [Symbol] name Name of the config parameter
60
+ # @param [Object] value Value for the config parameter
61
+ # @param [Proc] block Function which populates configuration for a sub-attribute
62
+ #
63
+ # @return [Object] attribute's value
64
+ def set_config(name, value, *args, &block)
65
+ case name
66
+ when :shell
67
+ handle_shell(value, &block)
68
+ else
69
+ super
70
+ end
71
+ end
72
+
73
+ # Set up default attributes for this configuration
74
+ #
75
+ # @return [Cliqr::Config::Command] Update config
76
+ def setup_defaults
77
+ super
78
+
79
+ add_shell
80
+ add_version
81
+ end
82
+
83
+ # Check if this configuration has shell action enabled
84
+ #
85
+ # @return [Boolean]
86
+ def shell?
87
+ @shell.enabled?
88
+ end
89
+
90
+ # Check if version is enabled for this command
91
+ #
92
+ # @return [Boolean] <tt>true</tt> if help is enabled
93
+ def version?
94
+ !@version.nil?
95
+ end
96
+
97
+ # Check if colors are enabled for this setting
98
+ def color?
99
+ @color == Cliqr::Config::ENABLE_CONFIG
100
+ end
101
+
102
+ private
103
+
104
+ # Handle configuration for shell config
105
+ #
106
+ # @param [Symbol] setting Enabled shell if the setting is <tt>BaseConfig::ENABLE_CONFIG</tt>
107
+ # @param [Proc] block Populate the shell's config in this block
108
+ #
109
+ # @return [Cliqr::Config::Shell] Newly created shell config
110
+ def handle_shell(setting, &block)
111
+ @shell = Shell.build(&block).tap do |shell_config|
112
+ unless setting.nil?
113
+ shell_config.enabled = setting
114
+ shell_config.finalize
115
+ end
116
+ end
117
+ end
118
+
119
+ # Add version command and option to this config
120
+ #
121
+ # @return [Cliqr::Config::Command] Updated config
122
+ def add_version
123
+ return self unless version?
124
+ add_action(Cliqr::Util.build_version_action(self)) unless action?('version')
125
+ add_option(Cliqr::Util.build_version_option(self)) unless option?('version')
126
+ end
127
+
128
+ # Add shell command
129
+ #
130
+ # @return [Cliqr::Config::Command] Updated config
131
+ def add_shell
132
+ return self unless shell?
133
+ add_action(Cliqr::Util.build_shell_action(self, @shell)) unless action?('shell')
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,81 @@
1
+ # encoding: utf-8
2
+
3
+ require 'delegate'
4
+
5
+ module Cliqr
6
+ module Config
7
+ # Used to separate all dsl methods in a separate block, thus allowing
8
+ # separation of concerns between non-dsl methods with dsl methods which
9
+ # improves maintainability.
10
+ #
11
+ # @api private
12
+ module DSL
13
+ # If a class includes this module, we add a few useful methods to that class
14
+ #
15
+ # @see http://www.ruby-doc.org/core/Module.html#method-i-included
16
+ #
17
+ # @return [Object]
18
+ def self.included(base)
19
+ base.class_eval do
20
+ def self.inherited(base)
21
+ transfer_validations(base)
22
+ DSL.included(base)
23
+ end
24
+
25
+ def self.transfer_validations(base)
26
+ base.validations.merge(validations)
27
+ end
28
+
29
+ # Entry point for invoking dsl methods
30
+ #
31
+ # @param [Hash] args Arguments to be used to build the DSL instance
32
+ #
33
+ # @param [Function] block The block to evaluate the DSL
34
+ #
35
+ # @return [Cliqr::DSL]
36
+ def self.build(*args, &block)
37
+ base = new(*args)
38
+ if block_given?
39
+ delegator = DSLDelegator.new(base)
40
+ delegator.instance_eval(&block)
41
+ end
42
+ base.finalize
43
+ base
44
+ end
45
+ end
46
+ end
47
+
48
+ # Delegates all DSL methods to the base class. Can be used to keep DSL
49
+ # methods separate from non-dsl methods. All implementing subclasses will
50
+ # have to implement a set_config method as described below
51
+ #
52
+ # class MyDSLClass
53
+ # include Cliqr::Config::DSL
54
+ #
55
+ # attr_accessor :attribute
56
+ #
57
+ # def set_config(name, value, &block)
58
+ # # handle config value for attribute "name"
59
+ # end
60
+ # end
61
+ #
62
+ # This will be invoked as:
63
+ #
64
+ # MyDSLClass.build do
65
+ # attribute 'some-value'
66
+ # end
67
+ class DSLDelegator < SimpleDelegator
68
+ # All dsl methods are handled dynamically by proxying through #set_config
69
+ #
70
+ # @param [Symbol] name Name of the method
71
+ # @param [Array] args Method arguments
72
+ # @param [Function] block A function to evaluate in the context of the method's arguments
73
+ #
74
+ # @return [Object] The return value of the proxied method
75
+ def method_missing(name, *args, &block)
76
+ __getobj__.set_config(name, args[0], *args[1..-1], &block)
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+
3
+ require 'cliqr/events/handler'
4
+
5
+ module Cliqr
6
+ module Config
7
+ # The configuration setting which defines a event
8
+ class Event < Cliqr::Config::Base
9
+ # Name of the event
10
+ #
11
+ # @return [String]
12
+ attr_accessor :name
13
+ validates :name,
14
+ non_empty_format: /^[a-zA-Z0-9_\-]+$/
15
+
16
+ # Event handler
17
+ #
18
+ # @return [Cliqr::Events::Handler]
19
+ attr_accessor :handler
20
+ validates :handler,
21
+ one_of: [
22
+ { type_of: Cliqr::Events::Handler },
23
+ { type_of: Proc }
24
+ ]
25
+
26
+ # New config instance with all attributes set as UNSET
27
+ def initialize
28
+ @name = UNSET
29
+ @handler = UNSET
30
+ end
31
+
32
+ # Finalize config by adding default values for unset values
33
+ #
34
+ # @return [Cliqr::Config::Base]
35
+ def finalize
36
+ @name = Config.get_if_unset(@name, '')
37
+ @handler = Config.get_if_unset(@handler, nil)
38
+
39
+ self
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,78 @@
1
+ # encoding: utf-8
2
+
3
+ require 'cliqr/config/event'
4
+
5
+ module Cliqr
6
+ module Config
7
+ # The configuration that enabled events for another configuration
8
+ class EventBased < Cliqr::Config::Base
9
+ # Events to listen for
10
+ #
11
+ # @return [Hash] A hash of <tt>String => Cliqr::Config::Event</tt>
12
+ attr_accessor :events
13
+ validates :events,
14
+ hash: true
15
+
16
+ # New instance of event based config
17
+ def initialize
18
+ @events = {}
19
+ end
20
+
21
+ # Add a event
22
+ #
23
+ # @param [Symbol] name Name of the attribute
24
+ # @param [String] event_name Event's name
25
+ # @param [Array] args Event handler
26
+ # @param [Proc] block Event handler function
27
+ #
28
+ # @return [Cliqr::Config::Event] Newly added event
29
+ def set_config(name, event_name, *args, &block)
30
+ case name
31
+ when :on
32
+ # if defined, args[0] will be the custom event handler class
33
+ handle_event(event_name, args[0], &block)
34
+ else
35
+ super
36
+ end
37
+ end
38
+
39
+ # Check if a event can be handled in this context
40
+ def handle?(name)
41
+ @events.key?(name.to_s)
42
+ end
43
+
44
+ # Get a event handler config by name
45
+ #
46
+ # @return [Cliqr::Config::Event]
47
+ def event(name)
48
+ @events[name.to_s]
49
+ end
50
+
51
+ private
52
+
53
+ # Handle the case when a event is added to the config
54
+ #
55
+ # @return [Cliqr::Events::Event]
56
+ def handle_event(event_name, event_class, &event_block)
57
+ fail Cliqr::Error::ValidationError, 'only one of event_class or event_block are allowed' \
58
+ if !event_class.nil? && block_given?
59
+
60
+ event_handler = event_class
61
+ event_handler = event_block if event_class.nil?
62
+ event = build_event(event_name, event_handler)
63
+ @events[event.name.to_s] = event
64
+ end
65
+
66
+ # Builds a event invocation handler wrapper
67
+ #
68
+ # @return [Cliqr::Events::Event]
69
+ def build_event(event_name, event_handler)
70
+ Cliqr::Config::Event.new.tap do |event|
71
+ event.name = event_name if event_name.is_a?(String) || event_name.is_a?(Symbol)
72
+ event.handler = event_handler
73
+ event.finalize
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,55 @@
1
+ # encoding: utf-8
2
+
3
+ require 'cliqr/config/event_based'
4
+
5
+ module Cliqr
6
+ # A extension for CLI module to group all config classes
7
+ #
8
+ # @api private
9
+ module Config
10
+ # The configuration setting to build a named configuration instance
11
+ class Named < Cliqr::Config::EventBased
12
+ # Name of the config instance
13
+ #
14
+ # @return [String]
15
+ attr_accessor :name
16
+ validates :name,
17
+ non_empty_format: /^[a-zA-Z0-9_\-]+$/
18
+
19
+ # Description for the config instance
20
+ #
21
+ # @return [String]
22
+ attr_accessor :description
23
+
24
+ # New config instance with all attributes set as UNSET
25
+ def initialize
26
+ super
27
+
28
+ @name = UNSET
29
+ @description = UNSET
30
+ end
31
+
32
+ # Finalize config by adding default values for unset values
33
+ #
34
+ # @return [Cliqr::Config::Named]
35
+ def finalize
36
+ @name = Config.get_if_unset(@name, '')
37
+ @description = Config.get_if_unset(@description, '')
38
+
39
+ self
40
+ end
41
+
42
+ # Check if a option's description is defined
43
+ #
44
+ # @return [Boolean] <tt>true</tt> if options' description is not null neither empty
45
+ def description?
46
+ !(@description.nil? || @description.empty?)
47
+ end
48
+
49
+ # Check if this config has a valid name
50
+ def name?
51
+ @name.is_a?(String) && !@name.empty?
52
+ end
53
+ end
54
+ end
55
+ end