belafonte 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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