loom-core 0.0.6 → 0.0.7
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/.rubocop.yml +31 -0
- data/Gemfile.lock +19 -1
- data/Rakefile +2 -0
- data/bin/loom +3 -0
- data/docs/architecture.jpg +0 -0
- data/gentags.sh +2 -0
- data/lib/loom/all.rb +1 -1
- data/lib/loom/config.rb +1 -1
- data/lib/loom/mods/mod_loader.rb +7 -2
- data/lib/loom/pattern/all.rb +1 -0
- data/lib/loom/pattern/definition_context.rb +4 -4
- data/lib/loom/pattern/dsl.rb +176 -119
- data/lib/loom/pattern/expanding_reference.rb +88 -6
- data/lib/loom/pattern/loader.rb +1 -17
- data/lib/loom/pattern/pattern.rb +52 -0
- data/lib/loom/pattern/reference.rb +17 -13
- data/lib/loom/pattern/reference_set.rb +71 -50
- data/lib/loom/runner.rb +46 -33
- data/lib/loom/runner/all.rb +2 -0
- data/lib/loom/runner/execution_context.rb +9 -0
- data/lib/loom/{dsl.rb → runner/sshkit_connector.rb} +5 -7
- data/lib/loom/shell.rb +4 -2
- data/lib/loom/shell/core.rb +16 -16
- data/lib/loom/version.rb +1 -1
- data/lib/loomext/coremods/exec.rb +1 -0
- data/loom.TAGS +797 -0
- data/loom.gemspec +1 -0
- data/spec/.loom/error_handling.loom +1 -0
- data/spec/.loom/fail.loom +27 -13
- data/spec/.loom/files.loom +1 -0
- data/spec/.loom/inventory.yml +3 -0
- data/spec/.loom/net.loom +1 -0
- data/spec/.loom/pattern_context.loom +1 -0
- data/spec/.loom/pkg.loom +1 -0
- data/spec/.loom/shell.loom +1 -0
- data/spec/.loom/test.loom +17 -4
- data/spec/.loom/user.loom +1 -0
- data/spec/.loom/vms.loom +1 -0
- data/spec/loom/pattern/dsl_spec.rb +3 -2
- data/spec/shared/loom_internals_helper.rb +1 -1
- data/spec/test_loom_spec.rb +102 -42
- data/test +15 -0
- metadata +25 -3
@@ -1,16 +1,98 @@
|
|
1
|
+
require "pry"
|
2
|
+
|
1
3
|
module Loom::Pattern
|
2
4
|
class ExpandingReference
|
3
5
|
|
4
|
-
|
6
|
+
RecursiveExpansionError = Class.new Loom::LoomError
|
7
|
+
|
8
|
+
# TODO: Ensure ExpandingReference and Reference stay in sync. Maybe create
|
9
|
+
# an inheritance hierarchy.
|
10
|
+
attr_reader :slug, :reference_slugs, :source_file, :desc, :pattern
|
5
11
|
|
6
|
-
|
12
|
+
##
|
13
|
+
# @param slug [String]: flattened colon separated slug name
|
14
|
+
# @param pattern [Loom::Pattern::Pattern]: a pattern responding to +expanded_slugs+
|
15
|
+
def initialize(slug, pattern, reference_set)
|
7
16
|
@slug = slug
|
8
|
-
@
|
9
|
-
|
17
|
+
@reference_set = reference_set
|
18
|
+
# TODO: Hmm... I tried to abstract the "weave" keyword from the
|
19
|
+
# "ExpandingReference" concept... but it leaked through. Think the
|
20
|
+
# `pattern.kind` based method name over.
|
21
|
+
@reference_slugs = pattern.weave.expanded_slugs
|
22
|
+
@desc = pattern.description
|
23
|
+
@pattern
|
24
|
+
end
|
25
|
+
|
26
|
+
def expand_slugs
|
27
|
+
slug_matchers = @reference_slugs.map do |s|
|
28
|
+
Matcher.get_matcher(s)
|
29
|
+
end
|
30
|
+
|
31
|
+
# O(MN) :(
|
32
|
+
expanded_slugs = @reference_slugs.flat_map do |s|
|
33
|
+
@reference_set.slugs.select { |s| slug_matchers.any? { |m| m.match?(s) } }
|
34
|
+
end.uniq
|
35
|
+
Loom.log.debug3(self) { "Loom::Pattern::ExpandingReference@reference_slugs+: #{@reference_slugs.join(",")}"}
|
36
|
+
Loom.log.debug3(self) { "Loom::Pattern::ExpandingReference+expanded_slugs+: #{expanded_slugs.join(",")}"}
|
37
|
+
|
38
|
+
expanded_refs = expanded_slugs.map { |s| @reference_set[s] }
|
39
|
+
expanded_refs.each do |r|
|
40
|
+
if r.is_a? ExpandingReference
|
41
|
+
Loom.log.error "recursive expansion for pattern[#{r.slug}] in weave[#{@slug}], i.e. only patterns are allowed in weaves"
|
42
|
+
raise RecursiveExpansionError, @slug
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
Loom.log.info { "expanded slug[#{@slug}] => #{expanded_slugs.join(",")}"}
|
47
|
+
expanded_slugs
|
10
48
|
end
|
11
49
|
|
12
|
-
|
13
|
-
|
50
|
+
private
|
51
|
+
# TODO: This can be made common to some utility directory if one emerges.
|
52
|
+
class Matcher
|
53
|
+
|
54
|
+
def self.get_matcher(slug)
|
55
|
+
matcher_module = [
|
56
|
+
GlobMatcher,
|
57
|
+
EqualityMatcher
|
58
|
+
].first { |m| m.handles_pattern? slug }
|
59
|
+
|
60
|
+
Class.new(Matcher).include(matcher_module).new(slug)
|
61
|
+
end
|
62
|
+
|
63
|
+
def initialize(loom_pattern_slug)
|
64
|
+
@my_slug = loom_pattern_slug
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
module GlobMatcher
|
69
|
+
MATCH_P = /(\*)$/
|
70
|
+
|
71
|
+
def self.handles_pattern?(p)
|
72
|
+
p.match? MATCH_P
|
73
|
+
end
|
74
|
+
|
75
|
+
def match?(your_pattern)
|
76
|
+
# TODO: This can be made RE2 compliant later.
|
77
|
+
unless GlobMatcher.handles_pattern?(@my_slug)
|
78
|
+
raise 'WTF? invalid pattern, must end in "*": %s' % @my_slug
|
79
|
+
end
|
80
|
+
|
81
|
+
prefix = @my_slug.to_s.gsub(MATCH_P, "")
|
82
|
+
Loom.log.debug2(self) { "GlobMatcher+match?+ #{@my_slug} #{your_pattern}, prefix: #{prefix}"}
|
83
|
+
your_pattern.to_s.start_with? prefix
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
module EqualityMatcher
|
88
|
+
def self.handles_pattern?(p)
|
89
|
+
true
|
90
|
+
end
|
91
|
+
|
92
|
+
def match?(your_pattern)
|
93
|
+
@my_slug == your_pattern
|
94
|
+
end
|
95
|
+
end
|
14
96
|
end
|
15
97
|
end
|
16
98
|
end
|
data/lib/loom/pattern/loader.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
module Loom::Pattern
|
2
2
|
|
3
3
|
SiteFileNotFound = Class.new Loom::LoomError
|
4
|
-
RecursiveExpansionError = Class.new Loom::LoomError
|
5
4
|
|
6
5
|
class Loader
|
7
6
|
class << self
|
@@ -48,22 +47,7 @@ module Loom::Pattern
|
|
48
47
|
end
|
49
48
|
|
50
49
|
def expand_refs(refs)
|
51
|
-
refs.flat_map
|
52
|
-
if ref.is_expanding?
|
53
|
-
expanded_refs = ref.reference_slugs.map { |s| get_pattern_ref(s) }
|
54
|
-
expanded_refs.each do |exp_ref|
|
55
|
-
if exp_ref.is_expanding?
|
56
|
-
Loom.log.error "error expanding pattern[#{exp_ref.slug}] in weave[#{ref.slug}], i.e. only patterns are allowed in weaves"
|
57
|
-
raise RecursiveExpansionError, ref.slug
|
58
|
-
end
|
59
|
-
end
|
60
|
-
Loom.log.info(
|
61
|
-
"expanded pattern #{ref.slug} to patterns: #{expanded_refs.map(&:slug).join(",")}")
|
62
|
-
expanded_refs
|
63
|
-
else
|
64
|
-
ref
|
65
|
-
end
|
66
|
-
end
|
50
|
+
refs.flat_map { |r| r.expand_slugs }.map { |s| @reference_set[s] }
|
67
51
|
end
|
68
52
|
end
|
69
53
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Loom::Pattern
|
2
|
+
# A value object represnting the .loom file pattern declarations. The
|
3
|
+
# difference between a Loom::Pattern::Pattern and Loom::Pattern::Reference is
|
4
|
+
# a pattern has no association to the context it should run in. It is simply a
|
5
|
+
# value object with pointers to its assigned values from the .loom
|
6
|
+
# file. However, a Reference includes it's DefinitionContext, including nested
|
7
|
+
# before/after/with_facts/let hooks.
|
8
|
+
class Pattern
|
9
|
+
|
10
|
+
KINDS = %i[pattern weave report]
|
11
|
+
.reduce({}) { |memo, k| memo.merge k => true }.freeze
|
12
|
+
|
13
|
+
# effectively, a list of `attr_readers` for the Pattern kind. but also used
|
14
|
+
# for validation
|
15
|
+
KIND_KWARGS = {
|
16
|
+
weave: [:expanded_slugs]
|
17
|
+
}.freeze
|
18
|
+
|
19
|
+
attr_reader :name, :description, :kind, :pattern_block
|
20
|
+
|
21
|
+
def initialize(name: nil, description: nil, kind: nil, **kind_kwargs, &block)
|
22
|
+
@name = name
|
23
|
+
@description = description
|
24
|
+
@kind = kind
|
25
|
+
@pattern_block = block
|
26
|
+
|
27
|
+
@valid_kwargs = KIND_KWARGS[kind]
|
28
|
+
kind_kwargs.each do |k, _|
|
29
|
+
raise "unknown kind_kwarg: #{k}" unless @valid_kwargs.include? k
|
30
|
+
end
|
31
|
+
@kind_properties_struct = OpenStruct.new kind_kwargs
|
32
|
+
end
|
33
|
+
|
34
|
+
# Adds methods:
|
35
|
+
# :is_weave?, is_pattern?, :is_reported?
|
36
|
+
# :weave, :patttern, :reported => returns the OpenStruct of KIND_KWARGS.
|
37
|
+
KINDS.keys.each do |k|
|
38
|
+
is_k_name = "is_#{k}?".intern
|
39
|
+
Loom.log.debug3(self) { "defining method Loom::Pattern::Pattern+#{is_k_name}+" }
|
40
|
+
define_method(is_k_name) { @kind == k }
|
41
|
+
|
42
|
+
k_name = k.intern
|
43
|
+
Loom.log.debug1(self) { "defining method Loom::Pattern::Pattern+#{k_name}+" }
|
44
|
+
define_method(k_name) do
|
45
|
+
if @kind != k_name
|
46
|
+
raise "invalid kwarg +#{k_name}+ for Pattern[#{@kind}]"
|
47
|
+
end
|
48
|
+
@kind_properties_struct.dup
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -1,22 +1,25 @@
|
|
1
1
|
module Loom::Pattern
|
2
|
+
# See Loom::Pattern::Pattern for the difference between refs and patterns.
|
2
3
|
class Reference
|
3
4
|
|
4
|
-
attr_reader :slug, :source_file, :desc
|
5
|
+
attr_reader :slug, :source_file, :desc, :pattern
|
5
6
|
|
6
|
-
def initialize(slug,
|
7
|
+
def initialize(slug, pattern, source_file, definition_ctx)
|
7
8
|
@slug = slug
|
8
|
-
@unbound_method = unbound_method
|
9
9
|
@source_file = source_file
|
10
10
|
@definition_ctx = definition_ctx
|
11
|
-
@desc = description
|
11
|
+
@desc = pattern.description
|
12
|
+
@pattern = pattern
|
12
13
|
end
|
13
14
|
|
14
|
-
|
15
|
-
|
15
|
+
# Used by Loom::Pattern::Loader to expand weaves. A Pattern::Reference it
|
16
|
+
# just expands to itself.
|
17
|
+
def expand_slugs
|
18
|
+
@slug
|
16
19
|
end
|
17
20
|
|
18
21
|
def call(shell_api, host_fact_set)
|
19
|
-
run_context = RunContext.new @
|
22
|
+
run_context = RunContext.new @pattern, @definition_ctx
|
20
23
|
|
21
24
|
fact_set = @definition_ctx.fact_set host_fact_set
|
22
25
|
Loom.log.debug5(self) {
|
@@ -30,7 +33,7 @@ module Loom::Pattern
|
|
30
33
|
begin
|
31
34
|
run_context.run shell_api, fact_set
|
32
35
|
rescue => e
|
33
|
-
error_msg = "error executing '#{slug}' in #{source_file}
|
36
|
+
error_msg = "error executing '#{slug}' in #{source_file} =>\n\t#{e}\n%s"
|
34
37
|
Loom.log.error(error_msg % e.backtrace.join("\n\t"))
|
35
38
|
raise
|
36
39
|
end
|
@@ -42,8 +45,8 @@ module Loom::Pattern
|
|
42
45
|
# A small class to bind the unbound_method to and provide context
|
43
46
|
# in the case of errors.
|
44
47
|
class RunContext
|
45
|
-
def initialize(
|
46
|
-
@
|
48
|
+
def initialize(pattern, definition_ctx)
|
49
|
+
@pattern = pattern
|
47
50
|
@definition_ctx = definition_ctx
|
48
51
|
end
|
49
52
|
|
@@ -55,7 +58,7 @@ module Loom::Pattern
|
|
55
58
|
Loom.log.debug1(self) { "before hooks => #{before_hooks}"}
|
56
59
|
before_hooks.each do |hook|
|
57
60
|
Loom.log.debug2(self) { "executing before hook => #{hook}"}
|
58
|
-
|
61
|
+
instance_exec shell_api, fact_set, &hook.block
|
59
62
|
end
|
60
63
|
|
61
64
|
# This is the entry point into calling patterns.
|
@@ -64,14 +67,15 @@ module Loom::Pattern
|
|
64
67
|
Loom.log.debug1(self) { "after hooks => #{after_hooks}" }
|
65
68
|
after_hooks.each do |hook|
|
66
69
|
Loom.log.debug2(self) { "executing after hook => #{hook}"}
|
67
|
-
|
70
|
+
instance_exec shell_api, fact_set, &hook.block
|
68
71
|
end
|
69
72
|
end
|
70
73
|
end
|
71
74
|
|
72
75
|
private
|
76
|
+
|
73
77
|
def apply_pattern(*args)
|
74
|
-
|
78
|
+
instance_exec(*args, &@pattern.pattern_block)
|
75
79
|
end
|
76
80
|
end
|
77
81
|
|
@@ -3,10 +3,13 @@
|
|
3
3
|
# into a reference set. There's also a lot of dark magic w/ generating
|
4
4
|
# stacktraces to get the correct .loom file line (but I forget if that's done
|
5
5
|
# here or in pattern/reference.rb maybe?)
|
6
|
+
|
7
|
+
# NB: The use of the word "mod" or "module" in this file probably means a
|
8
|
+
# ::Module, not a Loom::Mods::Module
|
6
9
|
module Loom::Pattern
|
7
10
|
|
8
11
|
DuplicatePatternRef = Class.new Loom::LoomError
|
9
|
-
|
12
|
+
NoReferenceForSlug = Class.new Loom::LoomError
|
10
13
|
InvalidPatternNamespace = Class.new Loom::LoomError
|
11
14
|
|
12
15
|
##
|
@@ -16,7 +19,11 @@ module Loom::Pattern
|
|
16
19
|
class << self
|
17
20
|
def load_from_file(path)
|
18
21
|
Loom.log.debug1(self) { "loading patterns from file => #{path}" }
|
19
|
-
|
22
|
+
builder(File.read(path), path).build
|
23
|
+
end
|
24
|
+
|
25
|
+
def builder(file_src, file_path)
|
26
|
+
Builder.create(file_src, file_path)
|
20
27
|
end
|
21
28
|
end
|
22
29
|
|
@@ -34,21 +41,20 @@ module Loom::Pattern
|
|
34
41
|
|
35
42
|
def get_pattern_ref(slug)
|
36
43
|
ref = @slug_to_ref_map[slug]
|
37
|
-
raise
|
44
|
+
raise NoReferenceForSlug, slug unless ref
|
38
45
|
ref
|
39
46
|
end
|
40
47
|
alias_method :[], :get_pattern_ref
|
41
48
|
|
42
49
|
def merge!(ref_set)
|
43
|
-
|
50
|
+
add_pattern_refs(ref_set.pattern_refs)
|
44
51
|
end
|
45
52
|
|
46
53
|
def add_pattern_refs(refs)
|
47
|
-
map = @slug_to_ref_map
|
48
54
|
refs.each do |ref|
|
49
55
|
Loom.log.debug2(self) { "adding ref to set => #{ref.slug}" }
|
50
|
-
raise DuplicatePatternRef, ref.slug if
|
51
|
-
|
56
|
+
raise DuplicatePatternRef, ref.slug if @slug_to_ref_map[ref.slug]
|
57
|
+
@slug_to_ref_map[ref.slug] = ref
|
52
58
|
end
|
53
59
|
end
|
54
60
|
|
@@ -57,83 +63,95 @@ module Loom::Pattern
|
|
57
63
|
|
58
64
|
class << self
|
59
65
|
def create(ruby_code, source_file)
|
66
|
+
# Creates an anonymous parent module in which to evaluate the .loom
|
67
|
+
# file src. This module acts as a global context for the .loom file.
|
68
|
+
# TODO: How should this be hardened?
|
60
69
|
shell_module = Module.new
|
61
70
|
shell_module.include Loom::Pattern
|
62
71
|
# TODO: I think this is my black magic for capturing stacktrace
|
63
72
|
# info... I forget the details. Add documentation.
|
73
|
+
# TODO: This is where I would need to hack into to auto-include
|
74
|
+
# Loom::Pattern in .loom file modules
|
64
75
|
shell_module.module_eval ruby_code, source_file, 1
|
65
76
|
shell_module.namespace ""
|
66
77
|
|
67
|
-
self.new
|
78
|
+
self.new shell_module, source_file
|
68
79
|
end
|
69
80
|
end
|
70
81
|
|
71
82
|
def initialize(shell_module, source_file)
|
72
83
|
@shell_module = shell_module
|
73
|
-
@pattern_mod_specs = pattern_mod_specs
|
74
84
|
@source_file = source_file
|
75
85
|
end
|
76
86
|
|
77
87
|
def build
|
78
88
|
ref_set = ReferenceSet.new
|
89
|
+
|
90
|
+
dsl_specs = create_dsl_specs
|
91
|
+
pattern_refs = create_pattern_refs dsl_specs, ref_set
|
92
|
+
|
79
93
|
ref_set.add_pattern_refs pattern_refs
|
80
94
|
ref_set
|
81
95
|
end
|
82
96
|
|
83
97
|
private
|
84
|
-
|
85
|
-
|
98
|
+
# TODO: I don't like passing in the ref set build target here.... but
|
99
|
+
# ExpandingReference needs it... Can I do this w/o an instance variable
|
100
|
+
# and w/o plumbing the param through methods?
|
101
|
+
def create_pattern_refs(dsl_specs, builder_target_ref_set)
|
102
|
+
dsl_specs.flat_map do |dsl_spec|
|
103
|
+
create_refs_for_dsl_spec dsl_spec, builder_target_ref_set
|
104
|
+
end
|
86
105
|
end
|
87
106
|
|
88
|
-
def
|
89
|
-
|
90
|
-
context = context_for_mod_spec mod_spec
|
107
|
+
def create_refs_for_dsl_spec(dsl_spec, builder_target_ref_set)
|
108
|
+
context = create_defn_context_for_dsl_spec dsl_spec
|
91
109
|
|
92
|
-
|
93
|
-
slug = compute_slug
|
110
|
+
dsl_spec[:dsl_builder].patterns.map do |pattern|
|
111
|
+
slug = compute_slug dsl_spec[:namespace_list], pattern.name
|
94
112
|
|
95
|
-
|
113
|
+
case pattern.kind
|
114
|
+
when :weave
|
96
115
|
Loom.log.debug2(self) { "adding ExpandingReference for weave: #{slug}" }
|
97
|
-
|
116
|
+
create_expanding_reference(pattern, slug, builder_target_ref_set)
|
98
117
|
else
|
99
118
|
Loom.log.debug2(self) { "adding Reference for pattern: #{slug}" }
|
100
|
-
|
119
|
+
create_pattern_reference(pattern, slug, context)
|
101
120
|
end
|
102
121
|
end
|
103
122
|
end
|
104
123
|
|
105
|
-
def
|
106
|
-
desc =
|
124
|
+
def create_expanding_reference(pattern, slug, ref_set)
|
125
|
+
desc = pattern.description
|
107
126
|
Loom.log.warn "no descripiton for weave => #{slug}" unless desc
|
108
127
|
|
109
|
-
ExpandingReference.new slug,
|
128
|
+
ExpandingReference.new slug, pattern, ref_set
|
110
129
|
end
|
111
130
|
|
112
|
-
def
|
113
|
-
|
114
|
-
desc = mod.pattern_description pattern_name
|
131
|
+
def create_pattern_reference(pattern, slug, context)
|
132
|
+
desc = pattern.description
|
115
133
|
Loom.log.warn "no descripiton for pattern => #{slug}" unless desc
|
116
134
|
|
117
|
-
Reference.new slug,
|
135
|
+
Reference.new slug, pattern, @source_file, context
|
118
136
|
end
|
119
137
|
|
120
|
-
|
121
|
-
|
122
|
-
|
138
|
+
# Creates a DefinitionContext for dsl_module by flattening and mapping
|
139
|
+
# parent ::Modules to a contextualized DefinitionContext.
|
140
|
+
def create_defn_context_for_dsl_spec(dsl_spec)
|
141
|
+
parents = dsl_spec[:parent_modules].find_all do |mod|
|
142
|
+
dsl_module? mod
|
123
143
|
end
|
124
144
|
parent_context = parents.reduce(nil) do |parent_ctx, parent_mod|
|
125
|
-
DefinitionContext.new parent_mod, parent_ctx
|
145
|
+
DefinitionContext.new parent_mod.dsl_builder, parent_ctx
|
126
146
|
end
|
127
|
-
|
128
|
-
mod = mod_spec[:module]
|
129
|
-
DefinitionContext.new mod, parent_context
|
147
|
+
DefinitionContext.new dsl_spec[:dsl_builder], parent_context
|
130
148
|
end
|
131
149
|
|
132
150
|
def compute_slug(namespace_list, pattern_method_name)
|
133
151
|
namespace_list.dup.push(pattern_method_name).join ":"
|
134
152
|
end
|
135
153
|
|
136
|
-
def
|
154
|
+
def create_namespace_list(pattern, parent_modules)
|
137
155
|
mods = parent_modules.dup << pattern
|
138
156
|
mods.reduce([]) do |memo, mod|
|
139
157
|
mod_name = if mod.respond_to?(:namespace) && mod.namespace
|
@@ -149,32 +167,35 @@ module Loom::Pattern
|
|
149
167
|
end
|
150
168
|
end
|
151
169
|
|
152
|
-
def
|
153
|
-
|
154
|
-
|
155
|
-
Loom.log.debug2(self) { "found pattern module => #{
|
156
|
-
|
170
|
+
def create_dsl_specs
|
171
|
+
dsl_mods = []
|
172
|
+
traverse_dsl_modules @shell_module do |dsl_mod, parent_modules|
|
173
|
+
Loom.log.debug2(self) { "found pattern module => #{dsl_mod}" }
|
174
|
+
|
175
|
+
dsl_builder = dsl_mod.dsl_builder
|
176
|
+
next if dsl_builder.patterns.empty?
|
157
177
|
|
158
|
-
|
159
|
-
|
160
|
-
:
|
161
|
-
:
|
162
|
-
:
|
163
|
-
:parent_modules => parent_modules.dup
|
178
|
+
dsl_mods << {
|
179
|
+
namespace_list: create_namespace_list(dsl_mod, parent_modules),
|
180
|
+
dsl_builder: dsl_builder,
|
181
|
+
dsl_module: dsl_mod,
|
182
|
+
parent_modules: parent_modules
|
164
183
|
}
|
165
184
|
end
|
166
|
-
|
185
|
+
dsl_mods
|
167
186
|
end
|
168
187
|
|
169
|
-
def
|
188
|
+
def dsl_module?(mod)
|
170
189
|
mod.included_modules.include? Loom::Pattern
|
171
190
|
end
|
172
191
|
|
173
|
-
|
192
|
+
# Recursive method to walk the tree of dsl_builders representative of the
|
193
|
+
# .loom file pattern modules
|
194
|
+
def traverse_dsl_modules(mod, pattern_parents=[], visited={}, &block)
|
174
195
|
return if visited[mod.name] # prevent cycles
|
175
196
|
visited[mod.name] = true
|
176
197
|
|
177
|
-
yield mod, pattern_parents.dup if
|
198
|
+
yield mod, pattern_parents.dup if dsl_module?(mod)
|
178
199
|
|
179
200
|
# Traverse all sub modules, even ones that aren't
|
180
201
|
# Loom::Pattern[s], since they might contain more sub modules
|
@@ -185,7 +206,7 @@ module Loom::Pattern
|
|
185
206
|
|
186
207
|
pattern_parents << mod
|
187
208
|
sub_modules.each do |sub_mod|
|
188
|
-
|
209
|
+
traverse_dsl_modules sub_mod, pattern_parents.dup, visited, &block
|
189
210
|
end
|
190
211
|
end
|
191
212
|
end
|