diecut 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|