bake 0.2.1 → 0.3.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
  SHA256:
3
- metadata.gz: 50c70583a03c13bc968e740c99eb323b533d650d2f4bdf0184cd3545ddbdfb01
4
- data.tar.gz: 50c90c5e197996e3e95f4cabd57a19e1bb0708e9acfe0302f8b33cf734acf0b7
3
+ metadata.gz: a957f57bf8396c2e06cb82745bf11c87ac287097c77b28500dc14a0abd9accf5
4
+ data.tar.gz: a4292acbdecb68e4d77b926c01347f09564b59db01d88e8705696ad5d2baab92
5
5
  SHA512:
6
- metadata.gz: 387d065fd0260080f352043f6288a59527944eb7d8b20af09285b39bafa7b6aedf3490ca497aadcdc4835cf0e2e518f1291998a3cc60292d6088b3eeba779b4c
7
- data.tar.gz: 99d16f46df97a26509933df503906d1117487e07ab26e9d526c609128e95902219478ec98fedf3cd9b2ef01603d8a5cdbcf8c280fff4bf9c8bbe5e69d73e6ec5
6
+ metadata.gz: 3f1af90dd73b4f104f09d8594ff3a36a84ddfbe24038c84207a3e714d850cae0b9d719bb6fc6875ede1cf3908f4b26ab02ec1562ae518e3dd2ab7fed1f0a9c2c
7
+ data.tar.gz: d1639bd8ca01c56450406055f51a22a70d46bffc8b999a04ea35e80180ed672a6ae7ab5bc37046359c563c1989e5a82aa04932521ad1b4f4ca119d8a8ad63883
data/bake.rb ADDED
@@ -0,0 +1,4 @@
1
+
2
+ # A test method.
3
+ def test
4
+ end
data/lib/bake/base.rb ADDED
@@ -0,0 +1,76 @@
1
+ # Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'recipe'
22
+ require_relative 'scope'
23
+
24
+ module Bake
25
+ class Base < Struct.new(:context)
26
+ def self.derive(path = [])
27
+ klass = Class.new(self)
28
+
29
+ klass.const_set(:PATH, path)
30
+
31
+ return klass
32
+ end
33
+
34
+ def self.to_s
35
+ if path = self.path
36
+ path.join(':')
37
+ else
38
+ super
39
+ end
40
+ end
41
+
42
+ def self.inspect
43
+ if path = self.path
44
+ "Bake::Base<#{path.join(':')}>"
45
+ else
46
+ super
47
+ end
48
+ end
49
+
50
+ def self.path
51
+ self.const_get(:PATH)
52
+ rescue
53
+ nil
54
+ end
55
+
56
+ def path
57
+ self.class.path
58
+ end
59
+
60
+ def call(*arguments)
61
+ self.context.call(*arguments)
62
+ end
63
+
64
+ def recipes
65
+ names = self.public_methods - Base.public_instance_methods
66
+
67
+ names.each do |name|
68
+ yield recipe_for(name)
69
+ end
70
+ end
71
+
72
+ def recipe_for(name)
73
+ Recipe.new(self, name)
74
+ end
75
+ end
76
+ end
@@ -26,12 +26,8 @@ require_relative '../context'
26
26
 
27
27
  module Bake
28
28
  module Command
29
- class Invoke < Samovar::Command
30
- self.description = "Invoke one or more commands."
31
-
32
- options do
33
- option "-d/--describe", "Describe what will be done, but don't do it.", default: false
34
- end
29
+ class Call < Samovar::Command
30
+ self.description = "Execute one or more commands."
35
31
 
36
32
  def bakefile
37
33
  @parent.bakefile
@@ -60,7 +56,7 @@ module Bake
60
56
 
61
57
  self.update_working_directory
62
58
 
63
- context.call(*@commands, **@options)
59
+ context.call(*@commands)
64
60
  end
65
61
  end
66
62
  end
@@ -19,6 +19,7 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  require 'samovar'
22
+ require 'set'
22
23
 
23
24
  module Bake
24
25
  module Command
@@ -49,41 +50,34 @@ module Bake
49
50
  end
50
51
  end
51
52
 
52
- def call
53
- first = true
54
- terminal = @parent.terminal
55
- context = @parent.context
53
+ def print_scope(terminal, scope)
56
54
  format_recipe = self.method(:format_recipe).curry
57
55
 
58
- unless context.empty?
59
- terminal.print_line(:loader, context)
56
+ scope.recipes do |recipe|
57
+ terminal.print_line
58
+ terminal.print_line("\t", format_recipe[recipe])
60
59
 
61
- context.each do |recipe|
62
- terminal.print_line
63
- terminal.print_line("\t", format_recipe[recipe])
64
- if description = recipe.description
65
- terminal.print_line("\t\t", :description, description)
66
- end
60
+ recipe.description.each do |line|
61
+ terminal.print_line("\t\t", :description, line)
67
62
  end
68
-
69
- terminal.print_line
70
63
  end
71
64
 
65
+ terminal.print_line
66
+ end
67
+
68
+ def call
69
+ first = true
70
+ terminal = @parent.terminal
71
+ context = @parent.context
72
+
73
+ print_scope(terminal, context.scope)
74
+
72
75
  context.loaders.each do |loader|
73
- terminal.print_line unless first
74
- first = false
75
-
76
76
  terminal.print_line(:loader, loader)
77
+
77
78
  loader.each do |path|
78
- if book = loader.lookup(path)
79
- # terminal.print_line("\t", book)
80
- book.each do |recipe|
81
- terminal.print_line
82
- terminal.print_line("\t", format_recipe[recipe])
83
- if description = recipe.description
84
- terminal.print_line("\t\t", :description, description)
85
- end
86
- end
79
+ if scope = loader.scope_for(path)
80
+ print_scope(terminal, scope)
87
81
  end
88
82
  end
89
83
 
@@ -21,7 +21,7 @@
21
21
  require 'samovar'
22
22
  require 'console/terminal'
23
23
 
24
- require_relative 'invoke'
24
+ require_relative 'call'
25
25
  require_relative 'list'
26
26
 
27
27
  module Bake
@@ -53,9 +53,9 @@ module Bake
53
53
  end
54
54
 
55
55
  nested :command, {
56
- 'invoke' => Invoke,
56
+ 'call' => Call,
57
57
  'list' => List,
58
- }, default: 'invoke'
58
+ }, default: 'call'
59
59
 
60
60
  def terminal(out = $stdout)
61
61
  terminal = Console::Terminal.for(out)
@@ -85,16 +85,10 @@ module Bake
85
85
  end
86
86
 
87
87
  def context
88
- loaders = Loaders.new
89
-
90
88
  if bakefile = self.bakefile
91
- context = Context.load(self.bakefile, loaders)
89
+ return Context.load(self.bakefile)
92
90
  else
93
- context = Context.new(loaders)
94
- end
95
-
96
- if loaders.empty?
97
- loaders.append_defaults(working_directory)
91
+ raise "Cannot find `bake.rb` file."
98
92
  end
99
93
 
100
94
  return context
data/lib/bake/context.rb CHANGED
@@ -18,86 +18,108 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
+ require_relative 'base'
22
+
21
23
  module Bake
22
- class Context < Book
23
- def initialize(loaders, **options)
24
- @loaders = loaders
24
+ class Context
25
+ def self.load(file_path, loaders = nil)
26
+ scope = Scope.load(file_path)
25
27
 
26
- @scope = []
28
+ unless loaders
29
+ if scope.respond_to?(:loaders)
30
+ loaders = scope.loaders
31
+ else
32
+ working_directory = File.dirname(file_path)
33
+ loaders = Loaders.default(working_directory)
34
+ end
35
+ end
27
36
 
28
- super(**options)
37
+ self.new(scope, loaders)
29
38
  end
30
39
 
31
- def to_s
32
- self.class.name
40
+ def initialize(scope, loaders, **options)
41
+ base = Base.derive
42
+ base.prepend(scope)
43
+
44
+ @loaders = loaders
45
+
46
+ @stack = []
47
+
48
+ @scopes = Hash.new do |hash, key|
49
+ hash[key] = scope_for(key)
50
+ end
51
+
52
+ @scope = base.new(self)
53
+ @scopes[[]] = @scope
54
+
55
+ @recipes = Hash.new do |hash, key|
56
+ hash[key] = recipe_for(key)
57
+ end
33
58
  end
34
59
 
60
+ attr :scope
35
61
  attr :loaders
36
62
 
37
63
  def call(*commands)
38
64
  while command = commands.shift
39
- if recipes = recipes_for(command)
40
- arguments, options = recipes.first.prepare(commands)
41
-
42
- recipes.each do |recipe|
43
- with(recipe) do
44
- yield recipe, arguments, options if block_given?
45
- recipe.call(self, *arguments, **options)
46
- end
47
- end
65
+ if recipe = @recipes[command]
66
+ arguments, options = recipe.prepare(commands)
67
+ recipe.call(*arguments, **options)
48
68
  else
49
69
  raise ArgumentError, "Could not find recipe for #{command}!"
50
70
  end
51
71
  end
52
72
  end
53
73
 
74
+ def lookup(command)
75
+ @recipes[command]
76
+ end
77
+
54
78
  private
55
79
 
56
- def with(recipe)
57
- @scope << recipe.book
80
+ def recipe_for(command)
81
+ path = command.split(":")
58
82
 
59
- yield
60
- ensure
61
- @scope.pop
62
- end
63
-
64
- def recipes_for(command)
65
- if command.is_a?(Symbol)
66
- recipes_for_relative_reference(command)
83
+ if scope = @scopes[path]
84
+ return scope.recipe_for(path.last)
67
85
  else
68
- recipes_for_absolute_reference(command)
86
+ *path, name = *path
87
+
88
+ if scope = @scopes[path]
89
+ return scope.recipe_for(name)
90
+ end
69
91
  end
92
+
93
+ return nil
70
94
  end
71
95
 
72
- def recipes_for_relative_reference(command)
73
- if scope = @scope.last
74
- if recipe = scope.lookup(command)
75
- return [recipe]
76
- end
96
+ def scope_for(path)
97
+ if base = base_for(path)
98
+ return base.new(self)
77
99
  end
78
100
  end
79
101
 
80
- def recipes_for_absolute_reference(command)
81
- path = command.split(":")
82
-
83
- recipes = []
84
-
85
- # Get the root level recipes:
86
- if recipe = self.recipe_for(path)
87
- recipes << recipe
88
- end
102
+ # @param scope [Array<String>] the path for the scope.
103
+ def base_for(path)
104
+ base = nil
89
105
 
90
106
  @loaders.each do |loader|
91
- if recipe = loader.recipe_for(path)
92
- recipes << recipe
107
+ if scope = loader.scope_for(path)
108
+ base ||= Base.derive(path)
109
+
110
+ base.prepend(scope)
93
111
  end
94
112
  end
95
113
 
96
- if recipes.empty?
97
- return nil
98
- else
99
- return recipes
100
- end
114
+ return base
115
+ end
116
+
117
+ def with!(scope)
118
+ @stack << scope
119
+
120
+ yield
121
+ ensure
122
+ @scope.pop
101
123
  end
102
124
  end
103
125
  end
data/lib/bake/loader.rb CHANGED
@@ -18,14 +18,13 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
- require_relative 'book'
21
+ require_relative 'scope'
22
22
 
23
23
  module Bake
24
24
  class Loader
25
25
  def initialize(root, name: nil)
26
26
  @root = root
27
27
  @name = name
28
- @cache = {}
29
28
  end
30
29
 
31
30
  def to_s
@@ -54,22 +53,14 @@ module Bake
54
53
  end
55
54
  end
56
55
 
57
- def lookup(path)
56
+ def scope_for(path)
58
57
  *directory, file = *path
59
58
 
60
59
  file_path = File.join(@root, directory, "#{file}.rb")
61
60
 
62
- unless @cache.key?(path)
63
- if File.exist?(file_path)
64
- book = Book.load(file_path, path)
65
-
66
- @cache[path] = book
67
- else
68
- @cache[path] = nil
69
- end
61
+ if File.exist?(file_path)
62
+ return Scope.load(file_path, path)
70
63
  end
71
-
72
- return @cache[path]
73
64
  end
74
65
  end
75
66
  end
data/lib/bake/loaders.rb CHANGED
@@ -20,11 +20,19 @@
20
20
 
21
21
  require 'console'
22
22
 
23
+ require_relative 'loader'
24
+
23
25
  module Bake
24
26
  class Loaders
25
27
  include Enumerable
26
28
 
27
- RECIPES_PATH = "recipes"
29
+ def self.default(working_directory)
30
+ loaders = self.new
31
+
32
+ loaders.append_defaults(working_directory)
33
+
34
+ return loaders
35
+ end
28
36
 
29
37
  def initialize
30
38
  @roots = {}
@@ -49,12 +57,24 @@ module Bake
49
57
  @ordered.each(&block)
50
58
  end
51
59
 
52
- def append_path(current = Dir.pwd, recipes_path: RECIPES_PATH, **options)
53
- recipes_path = File.join(current, recipes_path)
60
+ def append_path(current = Dir.pwd, **options)
61
+ recipes_path = File.join(current, "recipes")
62
+ bake_path = File.join(current, "bake")
63
+
64
+ if File.directory?(bake_path)
65
+ return insert(bake_path, **options)
66
+ end
54
67
 
55
68
  if File.directory?(recipes_path)
56
- insert(recipes_path, **options)
69
+ Console.logger.warn(self) do |buffer|
70
+ buffer.puts "Recipes path: #{recipes_path.inspect} is deprecated."
71
+ buffer.puts "Please use #{bake_path.inspect} instead."
72
+ end
73
+
74
+ return insert(recipes_path, **options)
57
75
  end
76
+
77
+ return false
58
78
  end
59
79
 
60
80
  def append_from_root(current = Dir.pwd, **options)
@@ -91,13 +111,7 @@ module Bake
91
111
 
92
112
  def insert(directory, **options)
93
113
  unless @roots.key?(directory)
94
- Console.logger.debug(self) do
95
- if path
96
- "Adding #{directory.inspect} for #{path.inspect}."
97
- else
98
- "Adding #{directory.inspect}"
99
- end
100
- end
114
+ Console.logger.debug(self) {"Adding #{directory.inspect}"}
101
115
 
102
116
  loader = Loader.new(directory, **options)
103
117
  @roots[directory] = loader
data/lib/bake/recipe.rb CHANGED
@@ -20,50 +20,55 @@
20
20
 
21
21
  module Bake
22
22
  class Recipe
23
- def initialize(book, name, description: nil, &block)
24
- @book = book
23
+ def initialize(scope, name, method = nil)
24
+ @scope = scope
25
25
  @name = name
26
- @description = description
27
- @block = block
28
- end
29
-
30
- attr :book
31
- attr :description
32
-
33
- def options?
34
- type, name = @block.parameters.last
26
+ @description = nil
35
27
 
36
- return type == :keyrest || type == :keyreq || type == :key
28
+ @method = method
37
29
  end
38
30
 
39
- def command
40
- if @book.path.empty?
41
- @name.to_s
42
- elsif @book.path.last.to_sym == @name
43
- @book.to_s
44
- else
45
- "#{@book}:#{@name}"
46
- end
31
+ attr :scope
32
+ attr :name
33
+
34
+ def method
35
+ @method ||= @scope.method(@name)
47
36
  end
48
37
 
49
38
  def parameters
50
- parameters = @block.parameters
39
+ parameters = method.parameters
51
40
 
52
41
  unless parameters.empty?
53
42
  return parameters
54
43
  end
55
44
  end
56
45
 
57
- def to_s
58
- if @description
59
- "#{self.command} #{@description}"
46
+ def options?
47
+ if parameters = self.parameters
48
+ type, name = self.parameters.last
49
+
50
+ return type == :keyrest || type == :keyreq || type == :key
51
+ end
52
+ end
53
+
54
+ def command
55
+ path = @scope.path
56
+
57
+ if path.empty?
58
+ @name.to_s
59
+ elsif path.last.to_sym == @name
60
+ path.join(':')
60
61
  else
61
- self.command
62
+ (path + [@name]).join(':')
62
63
  end
63
64
  end
64
65
 
66
+ def to_s
67
+ self.command
68
+ end
69
+
65
70
  def arity
66
- @block.arity
71
+ method.arity
67
72
  end
68
73
 
69
74
  def prepare(arguments)
@@ -90,12 +95,12 @@ module Bake
90
95
  return ordered, options
91
96
  end
92
97
 
93
- def call(context, *arguments, **options)
98
+ def call(*arguments, **options)
94
99
  if options?
95
- context.instance_exec(*arguments, **options, &@block)
100
+ @scope.send(@name, *arguments, **options)
96
101
  else
97
102
  # Ignore options...
98
- context.instance_exec(*arguments, &@block)
103
+ @scope.send(@name, *arguments)
99
104
  end
100
105
  end
101
106
 
@@ -106,5 +111,39 @@ module Bake
106
111
  puts "#{self}(#{arguments.join(", ")})"
107
112
  end
108
113
  end
114
+
115
+ def description
116
+ @description ||= read_description
117
+ end
118
+
119
+ private
120
+
121
+ def read_description
122
+ file, line_number = self.method.source_location
123
+
124
+ lines = File.readlines(file)
125
+ line_index = line_number - 1
126
+
127
+ # Legacy "recipe" syntax:
128
+ if match = lines[line_index].match(/description: "(.*?)"/)
129
+ return [match[1]]
130
+ end
131
+
132
+ description = []
133
+ line_index -= 1
134
+
135
+ # Extract comment preceeding method:
136
+ while line = lines[line_index]
137
+ if match = line.match(/^\s*\#\s?(.*?)$/)
138
+ description.unshift(match[1])
139
+ else
140
+ break
141
+ end
142
+
143
+ line_index -= 1
144
+ end
145
+
146
+ return description
147
+ end
109
148
  end
110
149
  end
@@ -21,53 +21,41 @@
21
21
  require_relative 'recipe'
22
22
 
23
23
  module Bake
24
- class Book
25
- def self.load(file_path, *arguments, **options)
26
- instance = self.new(*arguments, **options)
24
+ module Scope
25
+ def self.load(file_path, path = [])
26
+ scope = Module.new
27
+ scope.extend(self)
27
28
 
28
- instance.freeze
29
+ scope.const_set(:FILE_PATH, file_path)
30
+ scope.const_set(:PATH, path)
29
31
 
30
- instance.instance_eval(File.read(file_path), file_path)
32
+ scope.module_eval(File.read(file_path), file_path)
31
33
 
32
- return instance
34
+ return scope
33
35
  end
34
36
 
35
- def initialize(path = [], **options)
36
- @path = path
37
- @recipes = {}
37
+ def self.inspect
38
+ "Bake::Scope<#{self.const_get(:FILE_PATH)}>"
38
39
  end
39
40
 
40
- def empty?
41
- @recipes.empty?
42
- end
43
-
44
- def each(&block)
45
- @recipes.each_value(&block)
46
- end
47
-
48
- attr :path
49
- attr :recipes
50
-
51
- def to_s
52
- @path.join(':')
41
+ def recipe(name, **options, &block)
42
+ define_method(name, &block)
53
43
  end
54
44
 
55
- def lookup(name)
56
- @recipes[name.to_sym]
45
+ def recipes
46
+ names = self.instance_methods
47
+
48
+ names.each do |name|
49
+ yield recipe_for(name)
50
+ end
57
51
  end
58
52
 
59
- def recipe_for(path)
60
- if path.size == 1
61
- lookup(path.first)
62
- end
53
+ def path
54
+ self.const_get(:PATH)
63
55
  end
64
56
 
65
- def recipe(name, **options, &block)
66
- unless block_given?
67
- block = self.method(name)
68
- end
69
-
70
- @recipes[name] = Recipe.new(self, name, **options, &block)
57
+ def recipe_for(name)
58
+ Recipe.new(self, name, self.instance_method(name))
71
59
  end
72
60
  end
73
61
  end
data/lib/bake/version.rb CHANGED
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Bake
22
- VERSION = "0.2.1"
22
+ VERSION = "0.3.0"
23
23
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bake
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-03 00:00:00.000000000 Z
11
+ date: 2020-02-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: samovar
@@ -94,19 +94,21 @@ files:
94
94
  - README.md
95
95
  - Rakefile
96
96
  - bake.gemspec
97
+ - bake.rb
97
98
  - bin/bake
98
99
  - example.png
99
100
  - gems.rb
100
101
  - lib/bake.rb
101
- - lib/bake/book.rb
102
+ - lib/bake/base.rb
102
103
  - lib/bake/command.rb
103
- - lib/bake/command/invoke.rb
104
+ - lib/bake/command/call.rb
104
105
  - lib/bake/command/list.rb
105
106
  - lib/bake/command/top.rb
106
107
  - lib/bake/context.rb
107
108
  - lib/bake/loader.rb
108
109
  - lib/bake/loaders.rb
109
110
  - lib/bake/recipe.rb
111
+ - lib/bake/scope.rb
110
112
  - lib/bake/version.rb
111
113
  homepage: https://github.com/ioquatix/bake
112
114
  licenses:
@@ -128,7 +130,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
128
130
  - !ruby/object:Gem::Version
129
131
  version: '0'
130
132
  requirements: []
131
- rubygems_version: 3.0.6
133
+ rubygems_version: 3.1.2
132
134
  signing_key:
133
135
  specification_version: 4
134
136
  summary: A replacement for rake with a simpler syntax.