bake 0.19.0 → 0.21.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: 99b2c03a18fc4aa5cb423eb24baadefa827104d4f85c39d360284e6d086e9e3c
4
- data.tar.gz: ce5eb5f377f89d575535fae064465daabb1ce34eab618acf139b9c6c51d9c311
3
+ metadata.gz: a486a2d684d8417098b550d477c23b52d9ee41e364bdb3eba4abe94a34b7e4bb
4
+ data.tar.gz: d6ed531b2cb2aa138d3eef54eaef5d082a6b119b5d320bb77cb72c2bc360b802
5
5
  SHA512:
6
- metadata.gz: d538348c6853c183e713d5e431b7780f3641aa6c6c17a4cbd04a4ae505f8bb143788724b809d5f2745b0c3e9a5cb1a24fc2f56e799da7c8fc64ce02312580792
7
- data.tar.gz: 5d2bc47eaea3c6194d6c8ce8f076ea40dc37b6e3a636a37fc305e0a4d1b571925e4d3aa9f195fa8cd02404f9be938e8891b9a4f18416be543e00c0ad371e390c
6
+ metadata.gz: 77e365e561d39182941954d48fbafb0b85dafd7e7392b5edb5c254052483437729d1d4207355fae156daeac2c10e06c56c9da7dbad8d98eab7d0c32f4b9d5607
7
+ data.tar.gz: d8a8ffbafbc2797d96026921c77ae99e6b00a719cd66291d36067db1ec72d3c0c9031dc069c20b18ac50fa6841177a07b5303f4367c6aabb01f373babee71783
checksums.yaml.gz.sig CHANGED
Binary file
data/bin/bake CHANGED
@@ -28,6 +28,6 @@ require_relative '../lib/bake/command'
28
28
  begin
29
29
  Bake::Command.call
30
30
  rescue => error
31
- Console.logger.error(Bake::Command) {error}
31
+ Console.error(Bake::Command, error)
32
32
  exit 1
33
33
  end
@@ -5,8 +5,7 @@
5
5
 
6
6
  require 'samovar'
7
7
 
8
- require_relative '../loaders'
9
- require_relative '../loader'
8
+ require_relative '../registry'
10
9
  require_relative '../context'
11
10
 
12
11
  module Bake
@@ -80,21 +80,11 @@ module Bake
80
80
  terminal = @parent.terminal
81
81
  context = @parent.context
82
82
 
83
- if scope = context.scope
84
- printed = print_scope(terminal, context.scope) do
85
- terminal.print_line(:context, context)
86
- end
87
-
88
- if printed
89
- terminal.print_line
90
- end
91
- end
92
-
93
- context.loaders.each do |loader|
83
+ context.registry.each do |loader|
94
84
  printed = false
95
85
 
96
86
  loader.each do |path|
97
- if scope = loader.scope_for(path)
87
+ loader.scopes_for(path) do |scope|
98
88
  print_scope(terminal, scope, printed: printed) do
99
89
  terminal.print_line(:loader, loader)
100
90
  printed = true
data/lib/bake/context.rb CHANGED
@@ -5,6 +5,7 @@
5
5
  # Copyright, 2020, by Olle Jonsson.
6
6
 
7
7
  require_relative 'base'
8
+ require_relative 'registry'
8
9
 
9
10
  module Bake
10
11
  # The default file name for the top level bakefile.
@@ -45,57 +46,49 @@ module Bake
45
46
  # @path [String] A file-system path.
46
47
  def self.load(path = Dir.pwd)
47
48
  if bakefile_path = self.bakefile_path(path)
48
- scope = Scope.load(bakefile_path)
49
-
50
49
  working_directory = File.dirname(bakefile_path)
51
- loaders = Loaders.default(working_directory)
52
50
  else
53
- scope = nil
54
-
55
51
  working_directory = path
56
- loaders = Loaders.default(working_directory)
57
52
  end
58
53
 
59
- return self.new(loaders, scope, working_directory)
54
+ registry = Registry.default(working_directory, bakefile_path)
55
+ context = self.new(registry, working_directory)
56
+
57
+ context.bakefile
58
+
59
+ return context
60
60
  end
61
61
 
62
- # Initialize the context with the specified loaders.
63
- # @parameter loaders [Loaders]
64
- def initialize(loaders, scope = nil, root = nil)
65
- @loaders = loaders
66
-
67
- @stack = []
62
+ # Initialize the context with the specified registry.
63
+ # @parameter registry [Registry]
64
+ def initialize(registry, root = nil)
65
+ @registry = registry
66
+ @root = root
68
67
 
69
68
  @instances = Hash.new do |hash, key|
70
69
  hash[key] = instance_for(key)
71
70
  end
72
71
 
73
- @scope = scope
74
- @root = root
75
-
76
- if @scope
77
- base = Base.derive
78
- base.prepend(@scope)
79
-
80
- @instances[[]] = base.new(self)
81
- end
82
-
83
72
  @recipes = Hash.new do |hash, key|
84
73
  hash[key] = recipe_for(key)
85
74
  end
86
75
  end
87
76
 
88
- # The loaders which will be used to resolve recipes in this context.
89
- attr :loaders
77
+ def bakefile
78
+ @instances[[]]
79
+ end
90
80
 
91
- # The scope for the root {BAKEFILE}.
92
- attr :scope
81
+ # The registry which will be used to resolve recipes in this context.
82
+ attr :registry
93
83
 
94
84
  # The root path of this context.
95
85
  # @returns [String | Nil]
96
86
  attr :root
97
87
 
98
88
  # Invoke recipes on the context using command line arguments.
89
+ #
90
+ # e.g. `context.call("gem:release:version:increment", "0,0,1")`
91
+ #
99
92
  # @parameter commands [Array(String)]
100
93
  def call(*commands)
101
94
  last_result = nil
@@ -118,6 +111,8 @@ module Bake
118
111
  @recipes[command]
119
112
  end
120
113
 
114
+ alias [] lookup
115
+
121
116
  def to_s
122
117
  if @root
123
118
  "#{self.class} #{File.basename(@root)}"
@@ -135,9 +130,13 @@ module Bake
135
130
  def recipe_for(command)
136
131
  path = command.split(":")
137
132
 
133
+ # If the command is in the form `foo:bar`, we check two cases:
134
+ #
135
+ # (1) We check for an instance at path `foo:bar` and if it responds to `bar`.
138
136
  if instance = @instances[path] and instance.respond_to?(path.last)
139
137
  return instance.recipe_for(path.last)
140
138
  else
139
+ # (2) We check for an instance at path `foo` and if it responds to `bar`.
141
140
  *path, name = *path
142
141
 
143
142
  if instance = @instances[path] and instance.respond_to?(name)
@@ -158,12 +157,10 @@ module Bake
158
157
  def base_for(path)
159
158
  base = nil
160
159
 
161
- @loaders.each do |loader|
162
- if scope = loader.scope_for(path)
163
- base ||= Base.derive(path)
164
-
165
- base.prepend(scope)
166
- end
160
+ # For each loader, we check if it has a scope for the given path. If it does, we prepend it to the base:
161
+ @registry.scopes_for(path) do |scope|
162
+ base ||= Base.derive(path)
163
+ base.prepend(scope)
167
164
  end
168
165
 
169
166
  return base
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2020-2024, by Samuel Williams.
5
+
6
+ require 'console'
7
+
8
+ require_relative 'directory_loader'
9
+ require_relative 'bakefile_loader'
10
+
11
+ module Bake
12
+ # Structured access to the working directory and loaded gems for loading bakefiles.
13
+ module Registry
14
+ class Aggregate
15
+ include Enumerable
16
+
17
+ # Create a loader using the specified working directory.
18
+ # @parameter working_directory [String]
19
+ def self.default(working_directory, bakefile_path = nil)
20
+ registry = self.new
21
+
22
+ if bakefile_path
23
+ registry.append_bakefile(bakefile_path)
24
+ end
25
+
26
+ registry.append_defaults(working_directory)
27
+
28
+ return registry
29
+ end
30
+
31
+ # Initialize an empty array of registry.
32
+ def initialize
33
+ # Used to de-duplicated directories:
34
+ @roots = {}
35
+
36
+ # The ordered list of loaders:
37
+ @ordered = Array.new
38
+ end
39
+
40
+ # Whether any registry are defined.
41
+ # @returns [Boolean]
42
+ def empty?
43
+ @ordered.empty?
44
+ end
45
+
46
+ # Enumerate the registry in order.
47
+ def each(&block)
48
+ @ordered.each(&block)
49
+ end
50
+
51
+ def scopes_for(path, &block)
52
+ @ordered.each do |registry|
53
+ registry.scopes_for(path, &block)
54
+ end
55
+ end
56
+
57
+ def append_bakefile(path)
58
+ @ordered << BakefileLoader.new(path)
59
+ end
60
+
61
+ # Append a specific project path to the search path for recipes.
62
+ # The computed path will have `bake` appended to it.
63
+ # @parameter current [String] The path to add.
64
+ def append_path(current = Dir.pwd, **options)
65
+ bake_path = File.join(current, "bake")
66
+
67
+ if File.directory?(bake_path)
68
+ return insert(bake_path, **options)
69
+ end
70
+
71
+ return false
72
+ end
73
+
74
+ # Add registry according to the current working directory and loaded gems.
75
+ # @parameter working_directory [String]
76
+ def append_defaults(working_directory)
77
+ # Load recipes from working directory:
78
+ self.append_path(working_directory)
79
+
80
+ # Load recipes from loaded gems:
81
+ self.append_from_gems
82
+ end
83
+
84
+ # Enumerate all loaded gems and add them.
85
+ def append_from_gems
86
+ ::Gem.loaded_specs.each do |name, spec|
87
+ Console.debug(self) {"Checking gem #{name}: #{spec.full_gem_path}..."}
88
+
89
+ if path = spec.full_gem_path and File.directory?(path)
90
+ append_path(path, name: spec.full_name)
91
+ end
92
+ end
93
+ end
94
+
95
+ protected
96
+
97
+ def insert(directory, **options)
98
+ unless @roots.key?(directory)
99
+ Console.debug(self) {"Adding #{directory.inspect}"}
100
+
101
+ loader = DirectoryLoader.new(directory, **options)
102
+ @roots[directory] = loader
103
+ @ordered << loader
104
+
105
+ return true
106
+ end
107
+
108
+ return false
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2020-2024, by Samuel Williams.
5
+
6
+ require_relative '../scope'
7
+
8
+ module Bake
9
+ module Registry
10
+ class BakefileLoader
11
+ def initialize(path)
12
+ @path = path
13
+ end
14
+
15
+ def to_s
16
+ "#{self.class} #{@path}"
17
+ end
18
+
19
+ attr :path
20
+
21
+ def each(&block)
22
+ yield []
23
+ end
24
+
25
+ def scopes_for(path)
26
+ if path == []
27
+ yield Scope.load(@path, [])
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2020-2024, by Samuel Williams.
5
+
6
+ require_relative '../scope'
7
+
8
+ module Bake
9
+ module Registry
10
+ # Represents a directory which contains bakefiles.
11
+ class DirectoryLoader
12
+ # Initialize the loader with the specified root path.
13
+ # @parameter root [String] A file-system path.
14
+ def initialize(root, name: nil)
15
+ @root = root
16
+ @name = name
17
+ end
18
+
19
+ def to_s
20
+ "#{self.class} #{@name || @root}"
21
+ end
22
+
23
+ # The root path for this loader.
24
+ attr :root
25
+
26
+ # Enumerate all bakefiles within the loaders root directory.
27
+ #
28
+ # You can pass the yielded path to {scope_for} to load the corresponding {Scope}.
29
+ #
30
+ # @yields {|path| ...}
31
+ # @parameter path [String] The (relative) scope path.
32
+ def each
33
+ return to_enum unless block_given?
34
+
35
+ Dir.glob("**/*.rb", base: @root) do |file_path|
36
+ yield file_path.sub(/\.rb$/, '').split(File::SEPARATOR)
37
+ end
38
+ end
39
+
40
+ # Load the {Scope} for the specified relative path within this loader, if it exists.
41
+ # @parameter path [Array(String)] A relative path.
42
+ def scopes_for(path)
43
+ *directory, file = *path
44
+
45
+ file_path = File.join(@root, directory, "#{file}.rb")
46
+
47
+ if File.exist?(file_path)
48
+ yield Scope.load(file_path, path)
49
+ end
50
+ end
51
+ end
52
+
53
+ class FileLoader
54
+ def initialize(paths)
55
+ @paths = paths
56
+ end
57
+
58
+ def to_s
59
+ "#{self.class} #{@paths}"
60
+ end
61
+
62
+ attr :paths
63
+
64
+ def each(&block)
65
+ @paths.each_key(&block)
66
+ end
67
+
68
+ def scope_for(path)
69
+ if file_path = @paths[path]
70
+ if File.exist?(file_path)
71
+ return Scope.load(file_path, path)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2020-2024, by Samuel Williams.
5
+
6
+ require_relative 'registry/aggregate'
7
+
8
+ module Bake
9
+ # Structured access to the working directory and loaded gems for loading bakefiles.
10
+ module Registry
11
+ def self.default(...)
12
+ Aggregate.default(...)
13
+ end
14
+ end
15
+ end
data/lib/bake/scope.rb CHANGED
@@ -11,20 +11,23 @@ module Bake
11
11
  # Load the specified file into a unique scope module, which can then be included into a {Base} instance.
12
12
  def self.load(file_path, path = [])
13
13
  scope = Module.new
14
+
15
+ if scope.respond_to?(:set_temporary_name)
16
+ scope.set_temporary_name("#{self.name}[#{file_path}]")
17
+ end
18
+
14
19
  scope.extend(self)
15
20
 
16
21
  scope.const_set(:FILE_PATH, file_path)
17
22
  scope.const_set(:PATH, path)
18
23
 
24
+ # yield scope if block_given?
25
+
19
26
  scope.module_eval(File.read(file_path), file_path)
20
27
 
21
28
  return scope
22
29
  end
23
30
 
24
- def self.inspect
25
- "Bake::Scope<#{self.const_get(:FILE_PATH)}>"
26
- end
27
-
28
31
  # Recipes defined in this scope.
29
32
  #
30
33
  # @yields {|recipe| ...}
@@ -41,6 +44,12 @@ module Bake
41
44
  end
42
45
 
43
46
  # The path of the file that was used to {load} this scope.
47
+ def file_path
48
+ pp file_path_self: self
49
+ self.const_get(:FILE_PATH)
50
+ end
51
+
52
+ # The path of the scope, relative to the root of the context.
44
53
  def path
45
54
  self.const_get(:PATH)
46
55
  end
data/lib/bake/version.rb CHANGED
@@ -4,5 +4,5 @@
4
4
  # Copyright, 2020-2024, by Samuel Williams.
5
5
 
6
6
  module Bake
7
- VERSION = "0.19.0"
7
+ VERSION = "0.21.0"
8
8
  end
data/lib/bake.rb CHANGED
@@ -4,6 +4,5 @@
4
4
  # Copyright, 2020-2024, by Samuel Williams.
5
5
 
6
6
  require_relative 'bake/version'
7
- require_relative 'bake/loaders'
8
- require_relative 'bake/loader'
7
+ require_relative 'bake/registry'
9
8
  require_relative 'bake/context'
data/readme.md CHANGED
@@ -17,7 +17,17 @@ That being said, Rake and Bake can exist side by side in the same project.
17
17
 
18
18
  ## Usage
19
19
 
20
- Please see the [project documentation](https://ioquatix.github.io/bake/).
20
+ Please see the [project documentation](https://ioquatix.github.io/bake/) for more details.
21
+
22
+ - [Getting Started](https://ioquatix.github.io/bake/guides/getting-started/index) - This guide gives a general overview of `bake` and how to use it.
23
+
24
+ - [Command Line Interface](https://ioquatix.github.io/bake/guides/command-line-interface/index) - The `bake` command is broken up into two main functions: `list` and `call`.
25
+
26
+ - [Project Integration](https://ioquatix.github.io/bake/guides/project-integration/index) - This guide explains how to add `bake` to a Ruby project.
27
+
28
+ - [Gem Integration](https://ioquatix.github.io/bake/guides/gem-integration/index) - This guide explains how to add `bake` to a Ruby gem and export standardised tasks for use by other gems and projects.
29
+
30
+ - [Input and Output](https://ioquatix.github.io/bake/guides/input-and-output/index) - `bake` has built in tasks for reading input and writing output in different formats. While this can be useful for general processing, there are some limitations, notably that rich object representations like `json` and `yaml` often don't support stream processing.
21
31
 
22
32
  ## Contributing
23
33
 
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bake
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.19.0
4
+ version: 0.21.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -38,7 +38,7 @@ cert_chain:
38
38
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
39
39
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
40
40
  -----END CERTIFICATE-----
41
- date: 2024-01-25 00:00:00.000000000 Z
41
+ date: 2024-08-21 00:00:00.000000000 Z
42
42
  dependencies:
43
43
  - !ruby/object:Gem::Dependency
44
44
  name: bigdecimal
@@ -87,9 +87,11 @@ files:
87
87
  - lib/bake/command/top.rb
88
88
  - lib/bake/context.rb
89
89
  - lib/bake/documentation.rb
90
- - lib/bake/loader.rb
91
- - lib/bake/loaders.rb
92
90
  - lib/bake/recipe.rb
91
+ - lib/bake/registry.rb
92
+ - lib/bake/registry/aggregate.rb
93
+ - lib/bake/registry/bakefile_loader.rb
94
+ - lib/bake/registry/directory_loader.rb
93
95
  - lib/bake/scope.rb
94
96
  - lib/bake/types.rb
95
97
  - lib/bake/types/any.rb
@@ -112,7 +114,9 @@ homepage: https://github.com/ioquatix/bake
112
114
  licenses:
113
115
  - MIT
114
116
  metadata:
117
+ documentation_uri: https://ioquatix.github.io/bake/
115
118
  funding_uri: https://github.com/sponsors/ioquatix/
119
+ source_code_uri: https://github.com/ioquatix/bake.git
116
120
  post_install_message:
117
121
  rdoc_options: []
118
122
  require_paths:
@@ -121,14 +125,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
121
125
  requirements:
122
126
  - - ">="
123
127
  - !ruby/object:Gem::Version
124
- version: '3.0'
128
+ version: '3.1'
125
129
  required_rubygems_version: !ruby/object:Gem::Requirement
126
130
  requirements:
127
131
  - - ">="
128
132
  - !ruby/object:Gem::Version
129
133
  version: '0'
130
134
  requirements: []
131
- rubygems_version: 3.5.3
135
+ rubygems_version: 3.5.11
132
136
  signing_key:
133
137
  specification_version: 4
134
138
  summary: A replacement for rake with a simpler syntax.
metadata.gz.sig CHANGED
Binary file
data/lib/bake/loader.rb DELETED
@@ -1,48 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2020-2024, by Samuel Williams.
5
-
6
- require_relative 'scope'
7
-
8
- module Bake
9
- # Represents a directory which contains bakefiles.
10
- class Loader
11
- # Initialize the loader with the specified root path.
12
- # @parameter root [String] A file-system path.
13
- def initialize(root, name: nil)
14
- @root = root
15
- @name = name
16
- end
17
-
18
- def to_s
19
- "#{self.class} #{@name || @root}"
20
- end
21
-
22
- # The root path for this loader.
23
- attr :root
24
-
25
- # Enumerate all bakefiles within the loaders root directory.
26
- # @yields {|path| ...}
27
- # @parameter path [String] The Ruby source file path.
28
- def each
29
- return to_enum unless block_given?
30
-
31
- Dir.glob("**/*.rb", base: @root) do |file_path|
32
- yield file_path.sub(/\.rb$/, '').split(File::SEPARATOR)
33
- end
34
- end
35
-
36
- # Load the {Scope} for the specified relative path within this loader, if it exists.
37
- # @parameter path [Array(String)] A relative path.
38
- def scope_for(path)
39
- *directory, file = *path
40
-
41
- file_path = File.join(@root, directory, "#{file}.rb")
42
-
43
- if File.exist?(file_path)
44
- return Scope.load(file_path, path)
45
- end
46
- end
47
- end
48
- end
data/lib/bake/loaders.rb DELETED
@@ -1,110 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2020-2024, by Samuel Williams.
5
-
6
- require 'console'
7
-
8
- require_relative 'loader'
9
-
10
- module Bake
11
- # Structured access to the working directory and loaded gems for loading bakefiles.
12
- class Loaders
13
- include Enumerable
14
-
15
- # Create a loader using the specified working directory.
16
- # @parameter working_directory [String]
17
- def self.default(working_directory)
18
- loaders = self.new
19
-
20
- loaders.append_defaults(working_directory)
21
-
22
- return loaders
23
- end
24
-
25
- # Initialize an empty array of loaders.
26
- def initialize
27
- @roots = {}
28
- @ordered = Array.new
29
- end
30
-
31
- # Whether any loaders are defined.
32
- # @returns [Boolean]
33
- def empty?
34
- @ordered.empty?
35
- end
36
-
37
- # Add loaders according to the current working directory and loaded gems.
38
- # @parameter working_directory [String]
39
- def append_defaults(working_directory)
40
- # Load recipes from working directory:
41
- self.append_path(working_directory)
42
-
43
- # Load recipes from loaded gems:
44
- self.append_from_gems
45
- end
46
-
47
- # Enumerate the loaders in order.
48
- def each(&block)
49
- @ordered.each(&block)
50
- end
51
-
52
- # Append a specific project path to the search path for recipes.
53
- # The computed path will have `bake` appended to it.
54
- # @parameter current [String] The path to add.
55
- def append_path(current = Dir.pwd, **options)
56
- bake_path = File.join(current, "bake")
57
-
58
- if File.directory?(bake_path)
59
- return insert(bake_path, **options)
60
- end
61
-
62
- return false
63
- end
64
-
65
- # Search from the current working directory until a suitable bakefile is found and add it.
66
- # @parameter current [String] The path to start searching from.
67
- def append_from_root(current = Dir.pwd, **options)
68
- while current
69
- Console.logger.debug(self) {"Checking current #{current}..."}
70
-
71
- append_path(current, **options)
72
-
73
- parent = File.dirname(current)
74
-
75
- if current == parent
76
- break
77
- else
78
- current = parent
79
- end
80
- end
81
- end
82
-
83
- # Enumerate all loaded gems and add them.
84
- def append_from_gems
85
- ::Gem.loaded_specs.each do |name, spec|
86
- Console.logger.debug(self) {"Checking gem #{name}: #{spec.full_gem_path}..."}
87
-
88
- if path = spec.full_gem_path and File.directory?(path)
89
- append_path(path, name: spec.full_name)
90
- end
91
- end
92
- end
93
-
94
- protected
95
-
96
- def insert(directory, **options)
97
- unless @roots.key?(directory)
98
- Console.logger.debug(self) {"Adding #{directory.inspect}"}
99
-
100
- loader = Loader.new(directory, **options)
101
- @roots[directory] = loader
102
- @ordered << loader
103
-
104
- return true
105
- end
106
-
107
- return false
108
- end
109
- end
110
- end