trees 0.3.4 → 0.4.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 +4 -4
- data/lib/flags.rb +25 -0
- data/lib/line.rb +17 -2
- data/lib/trees.rb +34 -22
- data/lib/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b8afa25fe3a28ca015098f7a3417d41ce8d4a02e80bda91889b9e656fa0df35a
|
|
4
|
+
data.tar.gz: b52883d15bcd9ebc738c269d4461b035d3bf3d527ec92267b1bbf5eabd0c4fcc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 03dd4e5487d5d6d79ea979a80ac589240021bda0e71baed1a3789482b605bfbe748aef05cd1b168324e07896248bc86e24da0c956ab59edbd521cf18417819b6
|
|
7
|
+
data.tar.gz: e1cca79dfaf2810852075f1ce75f1f2bae7296cf154daaf1d85ecd791cc6dc8ddbc46e97bac122d101a655ffcbb443eb0b83442224cb2f15f26299eb71f0f2fe
|
data/lib/flags.rb
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Trees
|
|
4
|
+
module Flags
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def split(tokens)
|
|
8
|
+
args = tokens.take_while { !flag?(it) }
|
|
9
|
+
flags = tokens.drop(args.length).slice_before { flag?(it) }.map { flag(*it) }
|
|
10
|
+
return if flags.include?(nil)
|
|
11
|
+
|
|
12
|
+
[args, flags.to_h]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# A dash alone, like for stdin, is an arg.
|
|
16
|
+
def flag?(token) = token.start_with?('-') && token != '-'
|
|
17
|
+
|
|
18
|
+
def flag(token, *values)
|
|
19
|
+
return if values.size > 1
|
|
20
|
+
|
|
21
|
+
name, given = token.sub(/\A--?/, '').split('=', 2)
|
|
22
|
+
[name.tr('-', '_').to_sym, given || values.first || true]
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/line.rb
CHANGED
|
@@ -2,16 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
module Trees
|
|
4
4
|
class Line
|
|
5
|
-
attr_reader :path, :params
|
|
5
|
+
attr_reader :path, :params, :keywords
|
|
6
6
|
attr_accessor :summary, :example, :execute
|
|
7
7
|
|
|
8
|
-
def initialize(path:, params:
|
|
8
|
+
def initialize(path:, params: [], keywords: [])
|
|
9
9
|
@path = path
|
|
10
10
|
@params = params
|
|
11
|
+
@keywords = keywords
|
|
11
12
|
|
|
12
13
|
@summary = nil
|
|
13
14
|
@example = nil
|
|
14
15
|
@execute = nil
|
|
16
|
+
@defaults = {}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# The keyword arguments' values once the line's defined, which are their defaults, kept so that a flag that isn't
|
|
20
|
+
# given on a run is its default again, rather than its value from the last run.
|
|
21
|
+
def keep_defaults
|
|
22
|
+
@defaults = keywords.to_h { [it, execute.binding.local_variable_get(it)] } if execute
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Sets the execute block's params to the values, or else the keyword arguments' defaults, then runs it.
|
|
26
|
+
def run(values)
|
|
27
|
+
values = @defaults.merge(values)
|
|
28
|
+
params.each { |param| execute.binding.local_variable_set(param, values[param]) if values.key?(param) }
|
|
29
|
+
execute.call
|
|
15
30
|
end
|
|
16
31
|
end
|
|
17
32
|
end
|
data/lib/trees.rb
CHANGED
|
@@ -1,24 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative 'flags'
|
|
3
4
|
require_relative 'line'
|
|
4
5
|
require_relative 'trie'
|
|
5
6
|
|
|
6
7
|
module Trees
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
TOKEN_SEPARATOR = ' '.freeze
|
|
8
|
+
TOKEN_SEPARATOR = ' '
|
|
10
9
|
|
|
11
10
|
def line(path, &block)
|
|
12
11
|
current_path << path
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
@current_line = Line.new(path: current_path_joined, params: block.parameters.to_h)
|
|
16
|
-
|
|
17
|
-
lines[current_path_joined] = @current_line
|
|
18
|
-
trie.merge(line: @current_line)
|
|
12
|
+
defined = define_line(block:)
|
|
19
13
|
|
|
20
|
-
block.call if block_given?
|
|
14
|
+
block.call(**stub_required_keywords(block:)) if block_given?
|
|
21
15
|
|
|
16
|
+
defined.keep_defaults
|
|
22
17
|
current_path.pop
|
|
23
18
|
end
|
|
24
19
|
|
|
@@ -37,30 +32,47 @@ module Trees
|
|
|
37
32
|
end
|
|
38
33
|
alias x execute
|
|
39
34
|
|
|
35
|
+
# The tokens match a line as they are, or else its args do, and its flags, in any order, are its keyword arguments.
|
|
40
36
|
def run(tokens)
|
|
41
|
-
results
|
|
42
|
-
|
|
37
|
+
return true if execute_block(results: trie.match(tokens:))
|
|
38
|
+
|
|
39
|
+
args, flags = Flags.split(tokens)
|
|
40
|
+
return false if flags.nil? || flags.empty?
|
|
41
|
+
|
|
42
|
+
execute_block(results: trie.match(tokens: args), flags:)
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
private
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
# The deepest line that runs, and has a keyword argument for each flag.
|
|
48
|
+
def execute_block(results:, flags: {})
|
|
48
49
|
while results.count > 0
|
|
49
50
|
result = results.pop
|
|
50
51
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
result.line.execute.binding.local_variable_set(param, result.params[param])
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
result.line.execute.call
|
|
52
|
+
next unless result.line.execute
|
|
53
|
+
next unless (flags.keys - result.line.keywords).empty?
|
|
57
54
|
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
result.line.run(result.params.merge(flags))
|
|
56
|
+
return true
|
|
60
57
|
end
|
|
61
58
|
|
|
62
59
|
false
|
|
63
|
-
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def define_line(block:)
|
|
63
|
+
path = current_path.join(TOKEN_SEPARATOR)
|
|
64
|
+
keywords = block.parameters.filter_map { |type, name| name if %i[key keyreq].include?(type) }
|
|
65
|
+
@current_line = Line.new(path:, params: block.parameters.map(&:last), keywords:)
|
|
66
|
+
|
|
67
|
+
lines[path] = @current_line
|
|
68
|
+
trie.merge(line: @current_line)
|
|
69
|
+
@current_line
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# The "line" block defines the params that the "execute" child block will use later but doesn't itself execute user input.
|
|
73
|
+
def stub_required_keywords(block:)
|
|
74
|
+
block.parameters.filter_map { |type, name| [name, nil] if type == :keyreq }.to_h
|
|
75
|
+
end
|
|
64
76
|
|
|
65
77
|
def current_path
|
|
66
78
|
@current_path ||= []
|
data/lib/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: trees
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- maedi
|
|
@@ -17,6 +17,7 @@ executables: []
|
|
|
17
17
|
extensions: []
|
|
18
18
|
extra_rdoc_files: []
|
|
19
19
|
files:
|
|
20
|
+
- lib/flags.rb
|
|
20
21
|
- lib/line.rb
|
|
21
22
|
- lib/trees.rb
|
|
22
23
|
- lib/trie.rb
|
|
@@ -41,7 +42,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
41
42
|
- !ruby/object:Gem::Version
|
|
42
43
|
version: '0'
|
|
43
44
|
requirements: []
|
|
44
|
-
rubygems_version:
|
|
45
|
+
rubygems_version: 4.0.6
|
|
45
46
|
specification_version: 4
|
|
46
47
|
summary: A CLI framework where you write the literal terminal commands.
|
|
47
48
|
test_files: []
|