belafonte 0.1.2 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a460418210e2ac70ea041d21767a9e07d66a2a59
4
- data.tar.gz: 93cdbe5d558f4ad27929bcee53f9d3d4772a6a5a
3
+ metadata.gz: c8b79a1d44e0ead9355e7daf0091c3b93aac55fe
4
+ data.tar.gz: 7aa26f871377c9b8a0a110859500cb65f90f3c30
5
5
  SHA512:
6
- metadata.gz: 9b4299b8461f277f49c286e15a0d161e84bf4028733b58e50359773b3ac0c1e2b3c9096d0763354de1ab400976f4d7385467085ac73be8725d464f0f27ef3855
7
- data.tar.gz: b4b6256af663d2a3574ee1a7ece14e35af67832d0269078fe3c8cf1b61db7410baff18af87f9152d194480b6f81b532f20d412f4e63cbdabe399b9267bcaa157
6
+ metadata.gz: 7c5245a9afd12af2cb31ff4d5633afb8233db43ae1f02f9b0612f479b7869de05b144ba2321ce60faa35f12224a0bc88d3db15c52fdc77bb836fb99b918f85ee
7
+ data.tar.gz: 992f421cf4b967f43f0a7b6668f90cd333f55f0f948eb1acbbc9f2c200376c1cfe76936d588d6d0cba90455d6d9debefcb2e103f006f90b585a9bef9152c72ef
data/README.md CHANGED
@@ -26,6 +26,16 @@ Or install it yourself as:
26
26
 
27
27
  ## Usage ##
28
28
 
29
+ Belafonte can be used both to create traditional single-purpose applications
30
+ (like `cat`, `ls`, `make`, etc), but it can also be used to create "command
31
+ suite" applications (like `git`, `rails`, `heroku`, etc).
32
+
33
+ ### Traditional Applications ###
34
+
35
+ As mentioned above, "traditional" applications are single-purpose utilities.
36
+ They tend to do one thing, with the goal of doing that one thing exceptionally
37
+ well.
38
+
29
39
  ```ruby
30
40
  require 'belafonte'
31
41
 
@@ -113,11 +123,19 @@ end
113
123
  exit MyApp.new(ARGV).execute!
114
124
  ```
115
125
 
116
- ## Upcoming Features ##
126
+ ### Command Suite Applications ###
127
+
128
+ Command suite applications (CSAs) are, in the simplest scenario, a collection
129
+ of Traditional Applications that are collected under a wrapper to provide a
130
+ uniform user interface.
131
+
132
+ Belafonte supports this sort of application through mounting, which is very
133
+ similar in spirit to, say, mounting one Rack application under another. The API is the same as the Traditional App API with two exceptions:
117
134
 
118
- So as to allow for "command suite" utilities, I'm planning to allow for the mounting of one application into another, a-la Rack, Sinatra, Grape, etc.
135
+ * Use `mount App` to mount an application as a subcommand
136
+ * Apps that mount other apps cannot have :unlimited args
119
137
 
120
- The API for this is unstable, and I need to figure out some business logic, but it should look something like this:
138
+ Here's an example:
121
139
 
122
140
  ```ruby
123
141
  require 'belafonte'
data/lib/belafonte/app.rb CHANGED
@@ -1,12 +1,12 @@
1
- require 'optparse'
2
1
  require 'belafonte/dsl'
3
- require 'belafonte/errors'
4
- require 'belafonte/help'
2
+ require 'belafonte/rhythm'
5
3
 
6
4
  module Belafonte
7
5
  # An application container
8
6
  class App
9
7
  include Belafonte::DSL
8
+ include Belafonte::Helpers
9
+ include Belafonte::Rhythm
10
10
 
11
11
  attr_reader :argv, :stdin, :stdout, :stderr, :kernel
12
12
 
@@ -18,69 +18,5 @@ module Belafonte
18
18
  @kernel = kernel
19
19
  @parent = parent
20
20
  end
21
-
22
- def execute!
23
- (@parser = Parser.new(
24
- switches: configured_switches,
25
- options: configured_options,
26
- commands: configured_subcommands,
27
- arguments: configured_args,
28
- argv: @argv
29
- )).parsed.tap do |parsed|
30
- @switches = parsed[:switches]
31
- @options = parsed[:options]
32
- @arguments = parsed[:args]
33
- activate_help! if parsed[:help]
34
- end
35
-
36
- @command = arg(:command).shift if arg(:command)
37
-
38
- unless dispatch || show_help || run_handle
39
- stderr.puts "No handler for the provided command line"
40
- return 1
41
- end
42
-
43
- 0
44
- end
45
-
46
- private
47
- def parent
48
- @parent
49
- end
50
-
51
- def subcommand_instance(command)
52
- command_class = configured_subcommands.
53
- find {|subcommand| subcommand.info(:title) == command}
54
-
55
- return nil unless command_class
56
-
57
- command_class.new(arg(:command), stdin, stdout, stderr, kernel, self)
58
- end
59
-
60
- def dispatch
61
- return false if @command.nil?
62
- handler = subcommand_instance(@command)
63
-
64
- unless handler
65
- activate_help!
66
- return false
67
- end
68
-
69
- handler.activate_help! if help_active?
70
- handler.execute!
71
- true
72
- end
73
-
74
- def show_help
75
- return false unless help_active?
76
- stdout.print Belafonte::Help.content_for(self)
77
- true
78
- end
79
-
80
- def run_handle
81
- return false unless respond_to?(:handle)
82
- handle
83
- true
84
- end
85
21
  end
86
22
  end
@@ -18,6 +18,9 @@ module Belafonte
18
18
  argv = @argv.clone
19
19
  arguments.each do |arg|
20
20
  values = arg.process(argv)
21
+ if arg.unlimited? && values.empty?
22
+ values.push('')
23
+ end
21
24
  processed[arg.name] = values
22
25
  argv.shift(values.length)
23
26
  end
@@ -34,7 +37,7 @@ module Belafonte
34
37
  end
35
38
 
36
39
  def validate_processed_args
37
- raise Belafonte::Errors::TooFewArguments.new("You didn't provide enough arguments") if processed.values.any? {|arg| arg.empty?}
40
+ raise Belafonte::Errors::TooFewArguments.new("You didn't provide enough arguments") if processed.values.any? {|arg| arg.empty? && !arg.unlimited?}
38
41
  end
39
42
  end
40
43
  end
@@ -1,4 +1,3 @@
1
- require 'optparse'
2
1
  require 'belafonte/switch'
3
2
  require 'belafonte/option'
4
3
  require 'belafonte/argument'
@@ -7,7 +6,7 @@ require 'belafonte/errors'
7
6
  module Belafonte
8
7
  module DSL
9
8
  # Class methods for defining apps
10
- module ClassMethods
9
+ module Definition
11
10
  def meta
12
11
  @meta ||= {}
13
12
  end
@@ -49,12 +48,13 @@ module Belafonte
49
48
  end
50
49
 
51
50
  def arg(name, arg_options = {})
52
- args.last.tap do |arg|
53
- if arg && arg.unlimited?
54
- raise Belafonte::Errors::InvalidArgument.new("You may not add other arguments after an unlimited argument")
55
- else
56
- args.push(Belafonte::Argument.new(arg_options.merge({name: name})))
57
- end
51
+ if has_unlimited_arg?
52
+ raise Belafonte::Errors::InvalidArgument.new("You may not add other arguments after an unlimited argument")
53
+
54
+ else
55
+
56
+ args.push(Belafonte::Argument.new(arg_options.merge({name: name})))
57
+
58
58
  end
59
59
  end
60
60
 
@@ -70,6 +70,10 @@ module Belafonte
70
70
  raise Belafonte::Errors::CircularMount.new("An app cannot mount itself") if app == self
71
71
  subcommands.push(app)
72
72
  end
73
+
74
+ def has_unlimited_arg?
75
+ !(args.find {|arg| arg.unlimited?}).nil?
76
+ end
73
77
  end
74
78
  end
75
79
  end
data/lib/belafonte/dsl.rb CHANGED
@@ -1,14 +1,10 @@
1
- require 'belafonte/dsl/instance_methods'
2
- require 'belafonte/dsl/class_methods'
1
+ require 'belafonte/dsl/definition'
3
2
 
4
3
  module Belafonte
5
4
  # A DSL for making apps
6
5
  module DSL
7
6
  def self.included(klass)
8
- klass.extend(Belafonte::DSL::ClassMethods)
7
+ klass.extend(Belafonte::DSL::Definition)
9
8
  end
10
-
11
- include Belafonte::DSL::InstanceMethods
12
- #include Belafonte::DSL::Mountin
13
9
  end
14
10
  end
@@ -10,13 +10,21 @@ module Belafonte
10
10
 
11
11
  attr_reader :name, :short, :long, :description
12
12
 
13
+ def self.shortify(option)
14
+ "-#{option.to_s}"
15
+ end
16
+
17
+ def self.longify(option)
18
+ "--#{option.to_s}"
19
+ end
20
+
13
21
  def normalize_flag(flag)
14
22
  flag.to_s.strip.gsub(/\s+/, '-')
15
23
  end
16
24
 
17
25
  def initialize(options = {})
18
26
  options[:name].tap do |name|
19
- unless options[:name]
27
+ unless name
20
28
  raise Belafonte::Errors::NoName.new("Flag name cannot be blank")
21
29
  end
22
30
  @name = name.to_sym
@@ -47,11 +55,11 @@ module Belafonte
47
55
 
48
56
  private
49
57
  def shortify(option)
50
- shortened = "-#{option.to_s}"
58
+ self.class.shortify(option)
51
59
  end
52
60
 
53
61
  def longify(option)
54
- "--#{option.to_s}"
62
+ self.class.longify(option)
55
63
  end
56
64
 
57
65
  def flag_array(items)
@@ -1,3 +1,5 @@
1
+ require 'belafonte/flag'
2
+
1
3
  module Belafonte
2
4
  module Help
3
5
  module FlagExtensions
@@ -22,24 +22,24 @@ module Belafonte
22
22
  end
23
23
 
24
24
  def name_section
25
- "NAME\n#{Wrapomatic.new("#{app.display_title} - #{app.summary}").wrapped}\n"
25
+ "NAME\n#{Wrapomatic.wrap("#{app.display_title} - #{app.summary}", 1)}\n"
26
26
  end
27
27
 
28
28
  def synopsis
29
- synopsis = "\nSYNOPSIS\n#{Wrapomatic.new(app.full_path).wrapped}"
29
+ synopsis = "\nSYNOPSIS\n#{Wrapomatic.wrap(app.full_path, 1)}"
30
30
  if app.description
31
- synopsis += "\n\n#{Wrapomatic.wrap(app.display_description)}"
31
+ synopsis += "\n\n#{Wrapomatic.wrap(app.display_description, 1)}"
32
32
  end
33
33
  synopsis + "\n"
34
34
  end
35
35
 
36
36
  def options
37
- return '' unless app.has_flags?
38
37
  options = "\nOPTIONS\n"
39
38
  app.sorted_flags.each do |flag|
40
39
  flag.extend(FlagExtensions)
41
- options += "#{Wrapomatic.new(flag.signature).wrapped}"
40
+ options += "#{Wrapomatic.wrap(flag.signature, 1)}\n"
42
41
  end
42
+ options += "#{Wrapomatic.wrap('-h, --help - Shows this message', 1)}"
43
43
 
44
44
  options + "\n"
45
45
  end
@@ -50,7 +50,7 @@ module Belafonte
50
50
 
51
51
  app.sorted_commands.each do |command|
52
52
  command.extend(CommandExtensions)
53
- commands += "#{Wrapomatic.new("#{command.display_title} - #{command.display_summary}").wrapped}\n"
53
+ commands += "#{Wrapomatic.wrap("#{command.display_title} - #{command.display_summary}", 1)}\n"
54
54
  end
55
55
 
56
56
  commands + "\n"
@@ -0,0 +1,13 @@
1
+ module Belafonte
2
+ module Helpers
3
+ module Arguments
4
+ def args
5
+ @arguments ||= {}
6
+ end
7
+
8
+ def arg(arg)
9
+ args[arg]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ module Belafonte
2
+ module Helpers
3
+ module Flags
4
+ def switches
5
+ @switches ||= {}
6
+ end
7
+
8
+ def switch_active?(switch)
9
+ switches[switch]
10
+ end
11
+
12
+ def options
13
+ @options ||= {}
14
+ end
15
+
16
+ def option(option)
17
+ options[option]
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,33 @@
1
+ module Belafonte
2
+ module Helpers
3
+ module MetaData
4
+ def title
5
+ self.class.info(:title)
6
+ end
7
+
8
+ def summary
9
+ self.class.info(:summary)
10
+ end
11
+
12
+ def description
13
+ self.class.info(:description)
14
+ end
15
+
16
+ def configured_switches
17
+ self.class.switches
18
+ end
19
+
20
+ def configured_options
21
+ self.class.options
22
+ end
23
+
24
+ def configured_args
25
+ self.class.args
26
+ end
27
+
28
+ def configured_subcommands
29
+ self.class.subcommands
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,22 @@
1
+ module Belafonte
2
+ module Helpers
3
+ # Instance methods for apps
4
+ module Restricted
5
+ protected
6
+
7
+ def activate_help!
8
+ @help = true
9
+ end
10
+
11
+ private
12
+
13
+ def help
14
+ @help ||= false
15
+ end
16
+
17
+ def help_active?
18
+ help
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,15 @@
1
+ require 'belafonte/senora'
2
+
3
+ module Belafonte
4
+ module Helpers
5
+ module Sharing
6
+ def share(key, value)
7
+ Belafonte::Senora.store(key, value)
8
+ end
9
+
10
+ def partake(key)
11
+ Belafonte::Senora.retrieve(key)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module Belafonte
2
+ module Helpers
3
+ # Instance methods for apps
4
+ module Subcommands
5
+
6
+ def subcommands
7
+ @subcommands ||= []
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ require 'belafonte/helpers/meta_data'
2
+ require 'belafonte/helpers/sharing'
3
+ require 'belafonte/helpers/flags'
4
+ require 'belafonte/helpers/arguments'
5
+ require 'belafonte/helpers/subcommands'
6
+ require 'belafonte/helpers/restricted'
7
+
8
+ module Belafonte
9
+ module Helpers
10
+ include MetaData
11
+ include Sharing
12
+ include Flags
13
+ include Arguments
14
+ include Subcommands
15
+ include Restricted
16
+ end
17
+ end
@@ -24,10 +24,6 @@ module Belafonte
24
24
  }
25
25
  end
26
26
 
27
- def help
28
- parser.to_s
29
- end
30
-
31
27
  def parser
32
28
  @parser ||= OptionParser.new
33
29
  end
@@ -0,0 +1,87 @@
1
+ require 'optparse'
2
+ require 'belafonte/errors'
3
+ require 'belafonte/help'
4
+ require 'belafonte/parser'
5
+ require 'belafonte/helpers'
6
+ require 'belafonte/wrapomatic'
7
+
8
+ module Belafonte
9
+ module Rhythm
10
+ def execute!
11
+ (@parser = Parser.new(
12
+ switches: configured_switches,
13
+ options: configured_options,
14
+ commands: configured_subcommands,
15
+ arguments: configured_args,
16
+ argv: @argv
17
+ )).parsed.tap do |parsed|
18
+ @switches = parsed[:switches]
19
+ @options = parsed[:options]
20
+ @arguments = parsed[:args]
21
+ activate_help! if parsed[:help]
22
+ end
23
+
24
+ @command = arg(:command).shift if arg(:command)
25
+
26
+ begin
27
+ run_setup
28
+
29
+ unless dispatch || show_help || run_handle
30
+ stderr.puts "No handler for the provided command line"
31
+ return 1
32
+ end
33
+ rescue => uncaught_error
34
+ stderr.puts "The application encountered the following error:"
35
+ stderr.puts Wrapomatic.wrap(uncaught_error.to_s, 1)
36
+ return 255
37
+ end
38
+
39
+ 0
40
+ end
41
+
42
+ private
43
+ def parent
44
+ @parent
45
+ end
46
+
47
+ def subcommand_instance(command)
48
+ command_class = configured_subcommands.
49
+ find {|subcommand| subcommand.info(:title) == command}
50
+
51
+ return nil unless command_class
52
+
53
+ command_class.new(arg(:command), stdin, stdout, stderr, kernel, self)
54
+ end
55
+
56
+ def dispatch
57
+ return false if @command.nil?
58
+ handler = subcommand_instance(@command)
59
+
60
+ unless handler
61
+ activate_help!
62
+ return false
63
+ end
64
+
65
+ handler.activate_help! if help_active?
66
+ handler.execute!
67
+ true
68
+ end
69
+
70
+ def show_help
71
+ return false unless help_active?
72
+ stdout.print Belafonte::Help.content_for(self)
73
+ true
74
+ end
75
+
76
+ def run_handle
77
+ return false unless respond_to?(:handle)
78
+ handle
79
+ true
80
+ end
81
+
82
+ def run_setup
83
+ return nil unless respond_to?(:setup)
84
+ setup
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,19 @@
1
+ module Belafonte
2
+ module Senora
3
+ def self.store(key, value)
4
+ data[key] = value
5
+ end
6
+
7
+ def self.retrieve(key)
8
+ data[key]
9
+ end
10
+
11
+ def self.data
12
+ @data ||= {}
13
+ end
14
+
15
+ def self.reset
16
+ @data = {}
17
+ end
18
+ end
19
+ end
@@ -1,3 +1,3 @@
1
1
  module Belafonte
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -2,25 +2,18 @@ module Belafonte
2
2
  class Wrapomatic
3
3
  attr_reader :text, :lines, :indents, :columns
4
4
 
5
- def self.wrap(text, indents = 1, columns = 80)
5
+ def self.wrap(text, indents = 0, columns = 80)
6
6
  new(text, indents, columns).wrapped
7
7
  end
8
8
 
9
- def initialize(text, indents = 1, columns = 80)
10
- @text = text
9
+ def initialize(text, indents = 0, columns = 80)
10
+ @text = text.split("\n").join(' ')
11
11
  @indents = indents
12
12
  @columns = columns
13
13
  @lines = []
14
14
  indentomize
15
15
  end
16
16
 
17
- def refresh(text, indents = 1, columns = 80)
18
- @text = text
19
- @remainder = ''
20
- @lines = []
21
- indentomize
22
- end
23
-
24
17
  def wrapped
25
18
  lines.join("\n")
26
19
  end
@@ -28,9 +21,9 @@ module Belafonte
28
21
  private
29
22
 
30
23
  def indentomize
31
- begin
32
- @lines.push(next_line)
33
- end until next_line.nil?
24
+ until (line = next_line).nil?
25
+ @lines.push(line)
26
+ end
34
27
  end
35
28
 
36
29
  def next_line
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: belafonte
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dennis Walters
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-10-21 00:00:00.000000000 Z
11
+ date: 2015-10-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -109,8 +109,7 @@ files:
109
109
  - lib/belafonte/argument.rb
110
110
  - lib/belafonte/argument_processor.rb
111
111
  - lib/belafonte/dsl.rb
112
- - lib/belafonte/dsl/class_methods.rb
113
- - lib/belafonte/dsl/instance_methods.rb
112
+ - lib/belafonte/dsl/definition.rb
114
113
  - lib/belafonte/errors.rb
115
114
  - lib/belafonte/flag.rb
116
115
  - lib/belafonte/help.rb
@@ -118,9 +117,17 @@ files:
118
117
  - lib/belafonte/help/command_extensions.rb
119
118
  - lib/belafonte/help/flag_extensions.rb
120
119
  - lib/belafonte/help/generator.rb
121
- - lib/belafonte/helpers/tokens.rb
120
+ - lib/belafonte/helpers.rb
121
+ - lib/belafonte/helpers/arguments.rb
122
+ - lib/belafonte/helpers/flags.rb
123
+ - lib/belafonte/helpers/meta_data.rb
124
+ - lib/belafonte/helpers/restricted.rb
125
+ - lib/belafonte/helpers/sharing.rb
126
+ - lib/belafonte/helpers/subcommands.rb
122
127
  - lib/belafonte/option.rb
123
128
  - lib/belafonte/parser.rb
129
+ - lib/belafonte/rhythm.rb
130
+ - lib/belafonte/senora.rb
124
131
  - lib/belafonte/switch.rb
125
132
  - lib/belafonte/version.rb
126
133
  - lib/belafonte/wrapomatic.rb
@@ -1,98 +0,0 @@
1
- require 'belafonte/parser'
2
-
3
- module Belafonte
4
- module DSL
5
- # Instance methods for apps
6
- module InstanceMethods
7
- def title
8
- self.class.info(:title)
9
- end
10
-
11
- def summary
12
- self.class.info(:summary)
13
- end
14
-
15
- def description
16
- self.class.info(:description)
17
- end
18
-
19
- def configured_switches
20
- self.class.switches
21
- end
22
-
23
- def configured_options
24
- self.class.options
25
- end
26
-
27
- def configured_args
28
- self.class.args
29
- end
30
-
31
- def configured_subcommands
32
- self.class.subcommands
33
- end
34
-
35
- def switches
36
- @switches ||= {}
37
- end
38
-
39
- def switch_active(switch)
40
- switches[switch]
41
- end
42
-
43
- def options
44
- @options ||= {}
45
- end
46
-
47
- def option(option)
48
- options[option]
49
- end
50
-
51
- def args
52
- @arguments ||= {}
53
- end
54
-
55
- def arg(arg)
56
- args[arg]
57
- end
58
-
59
- def subcommands
60
- @subcommands ||= []
61
- end
62
-
63
- def estate
64
- @estate ||= {}
65
- end
66
-
67
- def bequeathed(name, value)
68
- estate[name] ||= value
69
- end
70
-
71
- def activate_help!
72
- @help = true
73
- end
74
-
75
- private
76
-
77
- def parser
78
- @parser
79
- end
80
-
81
- #def short(option)
82
- #"-#{option.to_s}"
83
- #end
84
-
85
- #def long(option)
86
- #"-#{short(option)}"
87
- #end
88
-
89
- def help
90
- @help ||= false
91
- end
92
-
93
- def help_active?
94
- help
95
- end
96
- end
97
- end
98
- end
@@ -1,10 +0,0 @@
1
- module Belafonte
2
- module Helpers
3
- # deprecated tokenizer
4
- module Tokens
5
- def command_tokens
6
- commands.keys
7
- end
8
- end
9
- end
10
- end