mister_bin 0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f1363a49f614a04f932d61c6e52efbb9266a7c68605d3c232e95eb8b75fec9f7
4
+ data.tar.gz: dc34308fd4e779d20488e365895a4e3ef64c87290a20e1874fb1583687dcd8eb
5
+ SHA512:
6
+ metadata.gz: d2e2f3a8fe7799258c4995c36f9bef36a92c69977ed46e36537e53a9b0db40f402aece3fad632e1acd0827f12be086603fe55785809eeeaf323e4fda5cc44e4e
7
+ data.tar.gz: 786af8b7fe27061c2232166ba49d656c3c7972039bd3303f81a7b63a0b242496820c1f8b0f37c8ad739e74d9e6828446090339c55d45a528dfbcf12f4c380ef2
data/README.md ADDED
@@ -0,0 +1,33 @@
1
+ Mister Bin
2
+ ==================================================
3
+
4
+ [![Gem](https://img.shields.io/gem/v/mister_bin.svg?style=flat-square)](https://rubygems.org/gems/mister_bin)
5
+ [![Build](https://img.shields.io/travis/DannyBen/mister_bin.svg?style=flat-square)](https://travis-ci.org/DannyBen/mister_bin)
6
+ [![Maintainability](https://img.shields.io/codeclimate/maintainability/DannyBen/mister_bin.svg?style=flat-square)](https://codeclimate.com/github/DannyBen/mister_bin)
7
+
8
+ ---
9
+
10
+ Build modular command line utilities.
11
+
12
+ ---
13
+
14
+ Installation
15
+ --------------------------------------------------
16
+
17
+ $ gem install mister_bin
18
+
19
+
20
+
21
+ Design Goals
22
+ --------------------------------------------------
23
+
24
+ - Provide an easy and minimalistic DSL for building command line utilities.
25
+ - Provide a mechanism for separating each subcommand to its separate file.
26
+ - Support the ability to extend a given command from different sources.
27
+
28
+
29
+
30
+ Usage
31
+ --------------------------------------------------
32
+
33
+ Soon
@@ -0,0 +1,21 @@
1
+ module MisterBin
2
+ class Command
3
+ attr_reader :command, :file, :type
4
+
5
+ def initialize(command, file)
6
+ @command = command
7
+ @file = file
8
+ @type = command =~ / / ? :secondary : :primary
9
+ end
10
+
11
+ def run(argv=[])
12
+ script = Script.new file
13
+ script.build_docopt
14
+ script.execute argv
15
+ end
16
+
17
+ def argv
18
+ command.split ' '
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,52 @@
1
+ module MisterBin
2
+
3
+ # This class handles listing and finding command files
4
+ class Commands
5
+ attr_reader :basename, :basedir
6
+
7
+ def initialize(basename, basedir='.')
8
+ @basename = basename
9
+ @basedir = basedir
10
+ end
11
+
12
+ def all
13
+ @all ||= all!
14
+ end
15
+
16
+ def names
17
+ all.keys
18
+ end
19
+
20
+ def find(query)
21
+ query = [query] unless query.is_a? Array
22
+ query_regex = /^#{query.join '.* '}/
23
+ keys = names.select { |k| k =~ /^#{query_regex}/ }
24
+ keys = names.select { |k| k =~ /^#{query.first}/ } if keys.empty?
25
+ keys.map { |k| [k, all[k]] }.to_h
26
+ end
27
+
28
+ def find_one(query)
29
+ result = find query
30
+ result.size == 1 ? result.values.first : false
31
+ end
32
+
33
+ private
34
+
35
+ def all!
36
+ result = {}
37
+ files.map do |file|
38
+ if file =~ /#{basename}-(.+)-(.+)\.rb/
39
+ command = "#{$1} #{$2}"
40
+ elsif file =~ /#{basename}-(.+)\.rb/
41
+ command = $1
42
+ end
43
+ result[command] = Command.new command, file
44
+ end
45
+ result
46
+ end
47
+
48
+ def files
49
+ @files ||= Dir["#{basedir}/#{basename}-*.rb"]
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,66 @@
1
+ require 'singleton'
2
+ require 'colsole'
3
+
4
+ module MisterBin
5
+
6
+ # This singleton class is responsible for generating a text string ready to be used
7
+ # by Docopt.
8
+ class DocoptMaker
9
+ include Singleton
10
+ include Colsole
11
+
12
+ attr_reader :usages, :options, :examples
13
+ attr_accessor :help, :version
14
+
15
+ def initialize
16
+ reset
17
+ end
18
+
19
+ def reset
20
+ @usages = []
21
+ @options = []
22
+ @examples = []
23
+ @version = '0.0.0'
24
+ @help = nil
25
+ end
26
+
27
+ def docopt
28
+ [help_string, usage_string, options_string, examples_string].join "\n"
29
+ end
30
+
31
+ private
32
+
33
+ def help_string
34
+ word_wrap help
35
+ end
36
+
37
+ def usage_string
38
+ result = ["", "Usage:"]
39
+ usages.each { |text| result << word_wrap(" #{text}") }
40
+ result.join "\n"
41
+ end
42
+
43
+ def options_string
44
+ result = ["", "Options:"]
45
+ options.each do |option|
46
+ result << " #{option[0]}"
47
+ result << word_wrap(" #{option[1]}")
48
+ result << ""
49
+ end
50
+
51
+ result << " -h --help"
52
+ result << " Show this help\n"
53
+ result << " --version"
54
+ result << " Show version number"
55
+ result.join "\n"
56
+ end
57
+
58
+ def examples_string
59
+ return '' if examples.empty?
60
+
61
+ result = ["", "Examples:"]
62
+ examples.each { |text| result << word_wrap(" #{text}") }
63
+ result.join "\n"
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,66 @@
1
+ module MisterBin
2
+ class Runner
3
+ attr_reader :basefile, :basedir, :name
4
+
5
+ def self.run(basefile, argv=[])
6
+ new(basefile).run argv
7
+ end
8
+
9
+ def initialize(basefile)
10
+ @basefile = basefile
11
+ @basedir = File.dirname basefile
12
+ @name = File.basename basefile
13
+ end
14
+
15
+ def run(argv=[])
16
+ if argv.empty?
17
+ show_subs
18
+ else
19
+ execute argv
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def execute(argv)
26
+ argv = expand_argv argv
27
+ command = commands.find_one argv[0..1]
28
+
29
+ if command
30
+ execute_command command, argv
31
+ else
32
+ puts "Unknown command: #{argv[0]}"
33
+ return 1
34
+ end
35
+ end
36
+
37
+ def execute_command(command, argv)
38
+ command.run argv
39
+ end
40
+
41
+ def show_subs
42
+ if commands.all.empty?
43
+ puts "No subcommands found"
44
+ else
45
+ puts "Usage:"
46
+ commands.names.each { |command| puts " #{name} #{command}" }
47
+ end
48
+
49
+ return 1
50
+ end
51
+
52
+ def commands
53
+ @commands ||= Commands.new name, basedir
54
+ end
55
+
56
+ def expand_argv(argv)
57
+ command = commands.find_one argv[0..1]
58
+ if command
59
+ argv.shift command.argv.size
60
+ command.argv + argv
61
+ else
62
+ argv
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,62 @@
1
+ require 'docopt'
2
+
3
+ module MisterBin
4
+ class Script
5
+ attr_reader :file, :action_block
6
+
7
+ def initialize(file)
8
+ @file = file
9
+ end
10
+
11
+ def build_docopt
12
+ DocoptMaker.instance.reset
13
+ instance_eval script
14
+ docopt
15
+ end
16
+
17
+ def execute(argv=[])
18
+ args = Docopt.docopt docopt, version: DocoptMaker.instance.version, argv: argv
19
+ exitcode = action_block.call args if action_block
20
+ exitcode.is_a?(Numeric) ? exitcode : 0
21
+ rescue Docopt::Exit => e
22
+ puts e.message
23
+ 1
24
+ end
25
+
26
+ def docopt
27
+ DocoptMaker.instance.docopt
28
+ end
29
+
30
+ # DSL
31
+
32
+ def help(text)
33
+ DocoptMaker.instance.help = text
34
+ end
35
+
36
+ def usage(text)
37
+ DocoptMaker.instance.usages << text
38
+ end
39
+
40
+ def option(flags, text)
41
+ DocoptMaker.instance.options << [flags, text]
42
+ end
43
+
44
+ def example(text)
45
+ DocoptMaker.instance.examples << text
46
+ end
47
+
48
+ def version(text)
49
+ DocoptMaker.instance.version = text
50
+ end
51
+
52
+ def action(&block)
53
+ @action_block = block
54
+ end
55
+
56
+ private
57
+
58
+ def script
59
+ @script ||= File.read file
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,3 @@
1
+ module MisterBin
2
+ VERSION = "0.0.1"
3
+ end
data/lib/mister_bin.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'mister_bin/commands'
2
+ require 'mister_bin/command'
3
+ require 'mister_bin/runner'
4
+
5
+ require 'mister_bin/script'
6
+ require 'mister_bin/docopt_maker'
7
+
8
+ require 'byebug' if ENV['BYEBUG']
metadata ADDED
@@ -0,0 +1,205 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mister_bin
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Danny Ben Shitrit
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-04-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: colsole
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.5'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: docopt
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.6'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: byebug
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '9.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '9.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rdoc
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '5.1'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '5.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.6'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.6'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec_fixtures
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.3'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: runfile
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.10'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.10'
111
+ - !ruby/object:Gem::Dependency
112
+ name: runfile-tasks
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.4'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.4'
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.15'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.15'
139
+ - !ruby/object:Gem::Dependency
140
+ name: yard
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '0.9'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '0.9'
153
+ - !ruby/object:Gem::Dependency
154
+ name: github_changelog_generator
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '1.14'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '1.14'
167
+ description: Build pluggable and modular command line tools with subcommands
168
+ email: db@dannyben.com
169
+ executables: []
170
+ extensions: []
171
+ extra_rdoc_files: []
172
+ files:
173
+ - README.md
174
+ - lib/mister_bin.rb
175
+ - lib/mister_bin/command.rb
176
+ - lib/mister_bin/commands.rb
177
+ - lib/mister_bin/docopt_maker.rb
178
+ - lib/mister_bin/runner.rb
179
+ - lib/mister_bin/script.rb
180
+ - lib/mister_bin/version.rb
181
+ homepage: https://github.com/dannyben/mister_bin
182
+ licenses:
183
+ - MIT
184
+ metadata: {}
185
+ post_install_message:
186
+ rdoc_options: []
187
+ require_paths:
188
+ - lib
189
+ required_ruby_version: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - ">="
192
+ - !ruby/object:Gem::Version
193
+ version: 2.4.0
194
+ required_rubygems_version: !ruby/object:Gem::Requirement
195
+ requirements:
196
+ - - ">="
197
+ - !ruby/object:Gem::Version
198
+ version: '0'
199
+ requirements: []
200
+ rubyforge_project:
201
+ rubygems_version: 2.7.6
202
+ signing_key:
203
+ specification_version: 4
204
+ summary: Modular command line framefowk
205
+ test_files: []