bake 0.2.1 → 0.3.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
  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.