diecut 0.0.1
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 +7 -0
- data/bin/diecut +10 -0
- data/gem_test_suite.rb +17 -0
- data/lib/diecut/caller-locations-polyfill.rb +18 -0
- data/lib/diecut/cli.rb +77 -0
- data/lib/diecut/configurable.rb +142 -0
- data/lib/diecut/context-handler.rb +77 -0
- data/lib/diecut/errors.rb +14 -0
- data/lib/diecut/linter.rb +177 -0
- data/lib/diecut/mediator.rb +79 -0
- data/lib/diecut/mill.rb +68 -0
- data/lib/diecut/mustache.rb +20 -0
- data/lib/diecut/plugin-description/context-default.rb +13 -0
- data/lib/diecut/plugin-description/option.rb +63 -0
- data/lib/diecut/plugin-description.rb +147 -0
- data/lib/diecut/plugin-loader.rb +189 -0
- data/lib/diecut/report.rb +136 -0
- data/lib/diecut/template-reducer.rb +88 -0
- data/lib/diecut/template-set.rb +108 -0
- data/lib/diecut/template.rb +58 -0
- data/lib/diecut/ui-applier.rb +71 -0
- data/lib/diecut/ui-config.rb +31 -0
- data/lib/diecut.rb +54 -0
- data/spec/cli_spec.rb +1 -0
- data/spec/configurable_spec.rb +20 -0
- data/spec/linter_spec.rb +132 -0
- data/spec/mill_spec.rb +52 -0
- data/spec/plugin_loader_spec.rb +109 -0
- data/spec/register_plugin_spec.rb +105 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/template-reducer_spec.rb +36 -0
- data/spec/template_set_spec.rb +22 -0
- data/spec/template_spec.rb +60 -0
- metadata +152 -0
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'tsort'
|
2
|
+
require 'diecut/template'
|
3
|
+
require 'diecut/mustache'
|
4
|
+
require 'diecut/configurable'
|
5
|
+
|
6
|
+
module Diecut
|
7
|
+
class TemplateSet
|
8
|
+
include TSort
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@templates = {}
|
12
|
+
@path_templates = {}
|
13
|
+
@breaking_cycles = {}
|
14
|
+
@partials = {}
|
15
|
+
@context_class = nil
|
16
|
+
@context = nil
|
17
|
+
@renderer = nil
|
18
|
+
end
|
19
|
+
attr_reader :partials, :templates, :path_templates
|
20
|
+
|
21
|
+
def add(path, contents)
|
22
|
+
template = Diecut::Template.new(path, contents)
|
23
|
+
@templates[path] = template
|
24
|
+
path_template = Diecut::Template.new("path for " + path, path)
|
25
|
+
@path_templates[path] = path_template
|
26
|
+
template.partials.each do |name, _|
|
27
|
+
@partials[name] = template
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def all_templates
|
32
|
+
@templates.values + @path_templates.values
|
33
|
+
end
|
34
|
+
|
35
|
+
def context_class
|
36
|
+
@context_class ||= Configurable.build_subclass("General context")
|
37
|
+
end
|
38
|
+
|
39
|
+
def context
|
40
|
+
@context ||= context_class.new
|
41
|
+
end
|
42
|
+
attr_writer :context
|
43
|
+
|
44
|
+
def is_partial?(tmpl)
|
45
|
+
@partials.has_key?(tmpl.path)
|
46
|
+
end
|
47
|
+
|
48
|
+
def tsort_each_node(&block)
|
49
|
+
@breaking_cycles.clear
|
50
|
+
@templates.each_value(&block)
|
51
|
+
end
|
52
|
+
|
53
|
+
def tsort_each_child(node)
|
54
|
+
node.partials.each do |name, _|
|
55
|
+
unless @breaking_cycles[name]
|
56
|
+
@breaking_cycles[name] = true
|
57
|
+
yield @templates[name]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def prepare
|
63
|
+
associate_partials
|
64
|
+
build_context
|
65
|
+
end
|
66
|
+
|
67
|
+
def renderer
|
68
|
+
@renderer ||= Mustache.new.tap do |mustache|
|
69
|
+
mustache.partials_hash = partials
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def results
|
74
|
+
context.check_required
|
75
|
+
|
76
|
+
tsort_each do |template|
|
77
|
+
next if is_partial?(template)
|
78
|
+
|
79
|
+
path = @path_templates[template.path]
|
80
|
+
context.copy_settings_to(template.context)
|
81
|
+
context.copy_settings_to(path.context)
|
82
|
+
|
83
|
+
yield path.render(renderer), template.render(renderer)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def associate_partials
|
88
|
+
partials = []
|
89
|
+
tsort_each do |template|
|
90
|
+
partials.each do |partial|
|
91
|
+
template.partial_context(partial)
|
92
|
+
end
|
93
|
+
if is_partial?(template)
|
94
|
+
partials << template
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def build_context
|
100
|
+
tsort_each do |template|
|
101
|
+
context_class.absorb_context(template.context_class)
|
102
|
+
end
|
103
|
+
@path_templates.each_value do |template|
|
104
|
+
context_class.absorb_context(template.context_class)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'diecut/configurable'
|
2
|
+
require 'diecut/template-reducer'
|
3
|
+
|
4
|
+
module Diecut
|
5
|
+
class Template
|
6
|
+
def initialize(path, template_string)
|
7
|
+
@path = path
|
8
|
+
@template_string = template_string
|
9
|
+
@reduced = nil
|
10
|
+
@context_class = nil
|
11
|
+
@context = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :path, :template_string
|
15
|
+
|
16
|
+
def partial_context(other)
|
17
|
+
reduced.partials.each do |path, nesting|
|
18
|
+
next unless path == other.path
|
19
|
+
add_subcontext(nesting, other.context_class)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_subcontext(nesting, other)
|
24
|
+
other.field_names.each do |field|
|
25
|
+
context_class.build_setting(nesting + [field])
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def context_class
|
30
|
+
@context_class ||= build_context_class
|
31
|
+
end
|
32
|
+
|
33
|
+
def reduced
|
34
|
+
@reduced ||= TemplateReducer.new(Mustache::Parser.new.compile(template_string))
|
35
|
+
end
|
36
|
+
|
37
|
+
def partials
|
38
|
+
reduced.partials
|
39
|
+
end
|
40
|
+
|
41
|
+
def build_context_class
|
42
|
+
klass = Configurable.build_subclass(path)
|
43
|
+
|
44
|
+
reduced.leaf_fields.each do |field|
|
45
|
+
klass.build_setting(field, reduced.sections.include?(field))
|
46
|
+
end
|
47
|
+
klass
|
48
|
+
end
|
49
|
+
|
50
|
+
def context
|
51
|
+
@context ||= context_class.new
|
52
|
+
end
|
53
|
+
|
54
|
+
def render(renderer)
|
55
|
+
renderer.render(template_string, context.to_hash)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Diecut
|
2
|
+
class UIApplier
|
3
|
+
attr_accessor :plugins, :ui, :context
|
4
|
+
|
5
|
+
# setup default values on ui
|
6
|
+
# setup dynamic defaults on context
|
7
|
+
# copy ui settings to context
|
8
|
+
# resolve context config
|
9
|
+
# confirm required
|
10
|
+
def apply
|
11
|
+
check_ui
|
12
|
+
basic_defaults
|
13
|
+
dynamic_defaults
|
14
|
+
copy_to_context
|
15
|
+
resolve_context
|
16
|
+
confirm_required
|
17
|
+
end
|
18
|
+
|
19
|
+
def check_ui
|
20
|
+
ui.check_required
|
21
|
+
end
|
22
|
+
|
23
|
+
def basic_defaults
|
24
|
+
context.setup_defaults
|
25
|
+
end
|
26
|
+
|
27
|
+
def dynamic_defaults
|
28
|
+
plugins.each do |plugin|
|
29
|
+
plugin.context_defaults.each do |default|
|
30
|
+
apply_dynamic_default(default)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def copy_to_context
|
36
|
+
plugins.each do |plugin|
|
37
|
+
plugin.options.each do |option|
|
38
|
+
copy_option(option)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def resolve_context
|
44
|
+
plugins.each do |plugin|
|
45
|
+
unless plugin.resolve_block.nil?
|
46
|
+
plugin.apply_resolve(ui, context)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def confirm_required
|
52
|
+
context.check_required
|
53
|
+
end
|
54
|
+
|
55
|
+
def apply_dynamic_default(default)
|
56
|
+
return if default.simple?
|
57
|
+
|
58
|
+
segment = context.walk_path(default.context_path).last
|
59
|
+
|
60
|
+
segment.value = default.compute_value(context)
|
61
|
+
end
|
62
|
+
|
63
|
+
def copy_option(option)
|
64
|
+
return unless option.has_context_path?
|
65
|
+
|
66
|
+
segment = context.walk_path(option.context_path).last
|
67
|
+
|
68
|
+
segment.value = ui.get_value(option.name.to_sym)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'diecut/configurable'
|
2
|
+
module Diecut
|
3
|
+
class UIConfig < Configurable
|
4
|
+
class << self
|
5
|
+
def options_hash
|
6
|
+
@options_hash ||= {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def description(name)
|
10
|
+
@options_hash.fetch(name).description
|
11
|
+
end
|
12
|
+
|
13
|
+
def required?(name)
|
14
|
+
field_metadata(name).is?(:required)
|
15
|
+
end
|
16
|
+
|
17
|
+
def default_for(name)
|
18
|
+
field_metadata(name).default_value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
super
|
24
|
+
setup_defaults
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_value(name)
|
28
|
+
self.class.field_metadata(name).value_on(self)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/diecut.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'diecut/mediator'
|
2
|
+
require 'diecut/plugin-description'
|
3
|
+
require 'diecut/plugin-loader'
|
4
|
+
|
5
|
+
module Diecut
|
6
|
+
class << self
|
7
|
+
def plugin_loader
|
8
|
+
@plugin_loader ||= PluginLoader.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def plugin_loader=(loader)
|
12
|
+
@plugin_loader = loader
|
13
|
+
end
|
14
|
+
|
15
|
+
def clear_plugins
|
16
|
+
@plugin_loader = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def load_plugins(prerelease = false)
|
20
|
+
plugin_loader.load_plugins(prerelease)
|
21
|
+
end
|
22
|
+
|
23
|
+
def plugins
|
24
|
+
plugin_loader.plugins
|
25
|
+
end
|
26
|
+
|
27
|
+
# Used in a `diecut_plugin.rb` file (either in the `lib/` of a gem, or at
|
28
|
+
# the local `~/.config/diecut/diecut_plugin.rb` to register a new plugin.
|
29
|
+
#
|
30
|
+
# @param name [String, Symbol]
|
31
|
+
# Names the plugin so that it can be toggled later
|
32
|
+
#
|
33
|
+
# @yieldparam description [PluginDescription]
|
34
|
+
# The description object to configure the plugin with.
|
35
|
+
def plugin(name, &block)
|
36
|
+
plugin_loader.describe_plugin(name, &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
def kinds
|
40
|
+
plugins.reduce([]) do |list, plugin|
|
41
|
+
list + plugin.kinds
|
42
|
+
end.uniq
|
43
|
+
end
|
44
|
+
|
45
|
+
def mediator(kind)
|
46
|
+
Mediator.new.tap do |med|
|
47
|
+
plugins.each do |plug|
|
48
|
+
next unless plug.has_kind?(kind)
|
49
|
+
med.add_plugin(plug)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/spec/cli_spec.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'diecut/cli'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'diecut/configurable'
|
2
|
+
|
3
|
+
describe Diecut::Configurable do
|
4
|
+
let :subclass do
|
5
|
+
Class.new(described_class){
|
6
|
+
setting :shallow
|
7
|
+
setting :deeply, Class.new(Diecut::Configurable){
|
8
|
+
setting :nested, Class.new(Diecut::Configurable){
|
9
|
+
setting :field
|
10
|
+
}
|
11
|
+
}
|
12
|
+
}.tap do |subclass|
|
13
|
+
subclass.target_name = "for something"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "inspects nicely" do
|
18
|
+
expect(subclass.inspect).to match(/Configurable.*something.*deeply\.nested\.field/)
|
19
|
+
end
|
20
|
+
end
|
data/spec/linter_spec.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'diecut/mill'
|
2
|
+
require 'diecut/linter'
|
3
|
+
|
4
|
+
describe Diecut::Mill do
|
5
|
+
let :mill do
|
6
|
+
Diecut::Mill.new("kind").tap do |mill|
|
7
|
+
mill.valise = valise
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
let :valise do
|
12
|
+
Valise::Set.define do
|
13
|
+
defaults do
|
14
|
+
file "{{testing}}.txt", "I am a {{thing}} for {{testing}}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
let :plugin do
|
20
|
+
Diecut::PluginDescription.new('dummy', 'dummy.rb').tap do |plugin|
|
21
|
+
plugin.option('testing') do |opt|
|
22
|
+
opt.goes_to('testing')
|
23
|
+
end
|
24
|
+
plugin.option('thing') do |opt|
|
25
|
+
opt.goes_to(['thing'])
|
26
|
+
end
|
27
|
+
plugin.default('thing', 15)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
let :option_colision_plugin do
|
32
|
+
Diecut::PluginDescription.new('icky', 'icky.rb').tap do |plugin|
|
33
|
+
plugin.default_off
|
34
|
+
plugin.option('context_colision') do |opt|
|
35
|
+
opt.goes_to('testing')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
let :default_override_plugin do
|
41
|
+
Diecut::PluginDescription.new('stinky', 'stinky.rb').tap do |plugin|
|
42
|
+
plugin.default_off
|
43
|
+
plugin.default('thing', 'fifteen')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
let :plugins do
|
48
|
+
[plugin, option_colision_plugin, default_override_plugin]
|
49
|
+
end
|
50
|
+
|
51
|
+
let :loader do
|
52
|
+
instance_double("Diecut::PluginLoader").tap do |loader|
|
53
|
+
allow(loader).to receive(:strict_sequence?).and_return(false)
|
54
|
+
allow(loader).to receive(:plugins).and_return(plugins)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
before :each do
|
59
|
+
allow(Diecut).to receive(:plugin_loader).and_return(loader)
|
60
|
+
|
61
|
+
plugins.each do |plugin|
|
62
|
+
mill.mediator.add_plugin(plugin)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
subject :linter do
|
67
|
+
Diecut::Linter.new(mill)
|
68
|
+
end
|
69
|
+
|
70
|
+
let :report do
|
71
|
+
linter.report
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "happy set of plugins" do
|
75
|
+
it "should produce a report" do
|
76
|
+
expect(report).to match(/Total QA failing reports: 0/)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "with an option collision" do
|
81
|
+
before :each do
|
82
|
+
mill.mediator.activate('icky')
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should produce a report" do
|
86
|
+
expect(report).to match(/Option collisions: FAIL/)
|
87
|
+
expect(report).to match(/Total QA failing reports:/)
|
88
|
+
expect(report).to match(/there's/)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "with a missing context field" do
|
93
|
+
before :each do
|
94
|
+
mill.mediator.activate('icky')
|
95
|
+
mill.mediator.deactivate('dummy')
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should produce a report" do
|
99
|
+
expect(report).to match(/Template fields all have settings: WARN/)
|
100
|
+
expect(report).to match(/Output field\s+Source file/)
|
101
|
+
expect(report).to match(/thing\s+{{testing}}.txt/)
|
102
|
+
expect(report).not_to match(/^\s*testing\b/)
|
103
|
+
expect(report).to match(/Total QA failing reports:/)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "with intentional override of default" do
|
108
|
+
before :each do
|
109
|
+
mill.mediator.activate("dummy")
|
110
|
+
mill.mediator.activate("stinky")
|
111
|
+
allow(loader).to receive(:strict_sequence?).with(plugin, default_override_plugin).and_return(true)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should produce a report" do
|
115
|
+
expect(report).to match(/Overridden context defaults: OK/)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "with accidental override of default" do
|
120
|
+
before :each do
|
121
|
+
mill.mediator.activate("dummy")
|
122
|
+
mill.mediator.activate("stinky")
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should produce a report" do
|
126
|
+
expect(report).to match(/Overridden context defaults: FAIL/)
|
127
|
+
expect(report).to match(/Output field\s+Default value\s+Source plugin/)
|
128
|
+
expect(report).to match(/thing\s+15\s+dummy/)
|
129
|
+
expect(report).to match(/Total QA failing reports:/)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
data/spec/mill_spec.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'diecut/mill'
|
2
|
+
|
3
|
+
describe Diecut::Mill do
|
4
|
+
subject :mill do
|
5
|
+
Diecut::Mill.new("kind").tap do |mill|
|
6
|
+
mill.valise = valise
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
let :valise do
|
11
|
+
Valise::Set.define do
|
12
|
+
defaults do
|
13
|
+
file "{{testing}}.txt", "I am a {{thing}} for {{testing}}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
let :plugin do
|
19
|
+
Diecut::PluginDescription.new('dummy', 'dummy.rb').tap do |plugin|
|
20
|
+
plugin.option('testing') do |opt|
|
21
|
+
opt.goes_to('testing')
|
22
|
+
end
|
23
|
+
plugin.option('thing') do |opt|
|
24
|
+
opt.goes_to(['thing'])
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
let :other_plugin do
|
30
|
+
Diecut::PluginDescription.new('icky', 'icky.rb')
|
31
|
+
end
|
32
|
+
|
33
|
+
before :each do
|
34
|
+
mill.mediator.add_plugin(plugin)
|
35
|
+
mill.mediator.add_plugin(other_plugin)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should render files" do
|
39
|
+
mill.activate_plugins do |name|
|
40
|
+
name == 'dummy'
|
41
|
+
end
|
42
|
+
ui = mill.user_interface
|
43
|
+
|
44
|
+
ui.testing = "checking"
|
45
|
+
ui.thing = "test file"
|
46
|
+
|
47
|
+
mill.churn(ui) do |path, contents|
|
48
|
+
expect(path).to eq "checking.txt"
|
49
|
+
expect(contents).to eq "I am a test file for checking"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'diecut/plugin-loader'
|
2
|
+
|
3
|
+
describe Diecut::PluginLoader do
|
4
|
+
let :root_gem do
|
5
|
+
instance_double('Gem::Specification', "root", :name => 'root', :matches_for_glob => ['/root_path/diecut_plugin.rb'],
|
6
|
+
:dependencies => [])
|
7
|
+
end
|
8
|
+
|
9
|
+
let :simple_dep do
|
10
|
+
instance_double('Gem::Specification', 'simple', :name => 'simple', :matches_for_glob => ['/simple_path/diecut_plugin.rb'],
|
11
|
+
:dependencies => [instance_double("Gem::Dependency", :name => "root")] )
|
12
|
+
end
|
13
|
+
|
14
|
+
let :side_dep do
|
15
|
+
instance_double('Gem::Specification', 'side', :name => 'side', :matches_for_glob => ['/side_path/diecut_plugin.rb'],
|
16
|
+
:dependencies => [
|
17
|
+
instance_double("Gem::Dependency", :name => "root"),
|
18
|
+
instance_double("Gem::Dependency", :name => "simple"),
|
19
|
+
instance_double("Gem::Dependency", :name => "cycle")
|
20
|
+
])
|
21
|
+
end
|
22
|
+
|
23
|
+
let :cycle_dep do
|
24
|
+
instance_double('Gem::Specification', 'cycle', :name => 'cycle', :matches_for_glob => ['/cycle_path/diecut_plugin.rb'],
|
25
|
+
:dependencies =>[ instance_double("Gem::Dependency", :name => "side") ])
|
26
|
+
end
|
27
|
+
|
28
|
+
let :gem_specs do
|
29
|
+
[root_gem, simple_dep, side_dep, cycle_dep]
|
30
|
+
end
|
31
|
+
|
32
|
+
let :plugin_defs do
|
33
|
+
{
|
34
|
+
"/root_path/diecut_plugin.rb" => proc{
|
35
|
+
loader.describe_plugin("root"){}
|
36
|
+
},
|
37
|
+
"/simple_path/diecut_plugin.rb" => proc{
|
38
|
+
loader.describe_plugin("simple"){}
|
39
|
+
},
|
40
|
+
"/side_path/diecut_plugin.rb" => proc{
|
41
|
+
loader.describe_plugin("side"){}
|
42
|
+
},
|
43
|
+
"/cycle_path/diecut_plugin.rb" => proc{
|
44
|
+
loader.describe_plugin("cycle"){}
|
45
|
+
},
|
46
|
+
"<DEFAULTS>:diecut_plugin.rb" => proc{
|
47
|
+
loader.describe_plugin("local"){}
|
48
|
+
}
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
let :valise do
|
53
|
+
Valise::Set.define do
|
54
|
+
defaults do
|
55
|
+
file "diecut_plugin.rb", "I am a thing for testing"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
subject :loader do
|
61
|
+
Diecut::PluginLoader.new.tap do |loader|
|
62
|
+
loader.local_valise = valise
|
63
|
+
current_caller = "no clue"
|
64
|
+
allow(loader).to receive(:caller_locations){ [current_caller] }
|
65
|
+
allow(loader).to receive(:latest_specs).and_return(gem_specs)
|
66
|
+
allow(loader).to receive(:require_plugin) {|path|
|
67
|
+
current_caller = double("Location", :absolute_path => path)
|
68
|
+
plugin_defs.fetch(path).call
|
69
|
+
}
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
let :root_plugin do
|
74
|
+
loader.plugins.find{|pl| pl.name == 'root' }
|
75
|
+
end
|
76
|
+
|
77
|
+
let :simple_plugin do
|
78
|
+
loader.plugins.find{|pl| pl.name == 'simple' }
|
79
|
+
end
|
80
|
+
|
81
|
+
let :side_plugin do
|
82
|
+
loader.plugins.find{|pl| pl.name == 'side' }
|
83
|
+
end
|
84
|
+
|
85
|
+
let :cycle_plugin do
|
86
|
+
loader.plugins.find{|pl| pl.name == 'cycle' }
|
87
|
+
end
|
88
|
+
|
89
|
+
let :local_plugin do
|
90
|
+
loader.plugins.find{|pl| pl.name == 'local' }
|
91
|
+
end
|
92
|
+
|
93
|
+
before :each do
|
94
|
+
loader.load_plugins
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
it "should load some plugins" do
|
99
|
+
expect(loader.plugins.length).to eq(5)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should trace sequencing" do
|
103
|
+
expect(loader.strict_sequence?(root_plugin, local_plugin)).to eq(true)
|
104
|
+
expect(loader.strict_sequence?(local_plugin, root_plugin)).to eq(false)
|
105
|
+
expect(loader.strict_sequence?(root_plugin, simple_plugin)).to eq(true)
|
106
|
+
expect(loader.strict_sequence?(root_plugin, cycle_plugin)).to eq(true)
|
107
|
+
expect(loader.strict_sequence?(side_plugin, cycle_plugin)).to eq(true)
|
108
|
+
end
|
109
|
+
end
|