chanko 2.2.1 → 3.0.0
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/.github/workflows/master_and_pr.yml +40 -0
- data/.gitignore +1 -1
- data/CHANGELOG.md +15 -1
- data/README.md +3 -43
- data/bin/setup +8 -0
- data/bin/test +7 -0
- data/chanko.gemspec +6 -5
- data/gemfiles/Gemfile_rails_6.1.rb +6 -0
- data/gemfiles/Gemfile_rails_7.0.rb +6 -0
- data/gemfiles/Gemfile_rails_7.1.rb +6 -0
- data/lib/chanko/config.rb +18 -4
- data/lib/chanko/function.rb +4 -13
- data/lib/chanko/loader.rb +124 -48
- data/lib/chanko/railtie.rb +9 -19
- data/lib/chanko/resolver/no_cache_file_system_resolver.rb +13 -0
- data/lib/chanko/test.rb +4 -0
- data/lib/chanko/unit/extender/extension.rb +0 -2
- data/lib/chanko/unit/extender.rb +0 -1
- data/lib/chanko/unit.rb +0 -12
- data/lib/chanko/version.rb +1 -1
- data/lib/generators/chanko/unit/templates/unit.rb.erb +3 -28
- data/lib/generators/chanko/unit/unit_generator.rb +22 -13
- data/spec/chanko/function_spec.rb +6 -30
- data/spec/chanko/invoker_spec.rb +2 -10
- data/spec/chanko/loader_spec.rb +14 -12
- data/spec/chanko/test_spec.rb +2 -5
- data/spec/chanko/unit_spec.rb +0 -63
- data/spec/controllers/application_controller_spec.rb +1 -1
- data/spec/dummy/app/assets/config/manifest.js +3 -0
- data/spec/dummy/app/units/entry_deletion/entry_deletion.rb +0 -16
- data/spec/dummy/app/views/units/example_unit +1 -0
- data/spec/dummy/config/application.rb +9 -1
- data/spec/dummy/config/boot.rb +4 -5
- data/spec/dummy/config/environment.rb +1 -1
- data/spec/dummy/config/environments/test.rb +8 -1
- data/spec/dummy/config/initializers/chanko_initializer.rb +0 -0
- data/spec/dummy/config/storage.yml +1 -0
- data/spec/fixtures/units/example_unit/example_unit.rb +2 -2
- data/spec/spec_helper.rb +19 -5
- metadata +54 -14
- data/.travis.yml +0 -8
- data/Gemfile +0 -11
- data/lib/chanko/unit/extender/active_record_class_methods.rb +0 -57
|
@@ -14,7 +14,7 @@ module <%= class_name %>
|
|
|
14
14
|
# ```
|
|
15
15
|
|
|
16
16
|
# ## raise_error
|
|
17
|
-
# `raise_error` is used to force an unit to raise up errors
|
|
17
|
+
# `raise_error` is used to force an unit to raise up errors occurred in invoking.
|
|
18
18
|
# You can force to raise up errors also by `Config.raise_error`.
|
|
19
19
|
#
|
|
20
20
|
# ```
|
|
@@ -34,36 +34,11 @@ module <%= class_name %>
|
|
|
34
34
|
# ```
|
|
35
35
|
|
|
36
36
|
# ## render
|
|
37
|
-
#
|
|
38
|
-
# So you can render <%= "#{directory}/views/_example.html.erb" %> in invoking.
|
|
39
|
-
#
|
|
37
|
+
# If you want to place the views path under the unit, create a symbolic link under app/views/units and refer to it.
|
|
40
38
|
# ```
|
|
41
39
|
# scope(:view) do
|
|
42
40
|
# function(:function_name) do
|
|
43
|
-
# render "/example", :foo => "bar"
|
|
44
|
-
# end
|
|
45
|
-
# end
|
|
46
|
-
# ```
|
|
47
|
-
|
|
48
|
-
# ## models
|
|
49
|
-
# In models block, you can expand model features by `expand` method.
|
|
50
|
-
# The expanded methods are available via unit proxy like `User.unit.active`,
|
|
51
|
-
# `User.find(params[:id]).unit.active?` or `User.unit.gc_all_soft_deleted_users`.
|
|
52
|
-
#
|
|
53
|
-
# ```
|
|
54
|
-
# models do
|
|
55
|
-
# expand(:User) do
|
|
56
|
-
# scope :active, lambda { where(:deleted_at => nil) }
|
|
57
|
-
#
|
|
58
|
-
# def active?
|
|
59
|
-
# deleted_at.nil?
|
|
60
|
-
# end
|
|
61
|
-
#
|
|
62
|
-
# class_methods do
|
|
63
|
-
# def gc_all_soft_deleted_users
|
|
64
|
-
# where.not(deleted_at: nil).delete_all
|
|
65
|
-
# end
|
|
66
|
-
# end
|
|
41
|
+
# render "/units/<%= file_name.underscore %>/example", :foo => "bar"
|
|
67
42
|
# end
|
|
68
43
|
# end
|
|
69
44
|
# ```
|
|
@@ -6,44 +6,53 @@ module Chanko
|
|
|
6
6
|
source_root File.expand_path("../templates", __FILE__)
|
|
7
7
|
|
|
8
8
|
def create_unit_directory
|
|
9
|
-
empty_directory(
|
|
9
|
+
empty_directory(unit_directory)
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def create_unit_file
|
|
13
|
-
template("unit.rb.erb", "#{
|
|
13
|
+
template("unit.rb.erb", "#{unit_directory}/#{file_name}.rb")
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
def
|
|
17
|
-
create_file("#{
|
|
16
|
+
def create_views_unit_directory
|
|
17
|
+
create_file("#{unit_directory}/views/.gitkeep", "")
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
ASSETS_TYPES.each do |type|
|
|
21
|
-
define_method("create_#{type}
|
|
22
|
-
create_file("#{
|
|
21
|
+
define_method("create_#{type}_unit_directory") do
|
|
22
|
+
create_file("#{unit_directory}/#{type}/.gitkeep", "")
|
|
23
23
|
end
|
|
24
|
-
end
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
define_method("create_#{type}_symlink") do
|
|
25
|
+
define_method("create_#{type}_unit_symlink") do
|
|
28
26
|
create_assets_symlink(type)
|
|
29
27
|
end
|
|
30
28
|
end
|
|
31
29
|
|
|
30
|
+
def create_views_symlink
|
|
31
|
+
from = "app/views/#{units_directory_name}/#{file_name}"
|
|
32
|
+
to = "../../../#{relative_unit_directory}/views"
|
|
33
|
+
create_link(from, to)
|
|
34
|
+
end
|
|
35
|
+
|
|
32
36
|
private
|
|
33
37
|
|
|
34
38
|
def create_assets_symlink(type)
|
|
35
|
-
from = "app/assets/#{type}/#{
|
|
36
|
-
to = "../../../../#{
|
|
39
|
+
from = "app/assets/#{type}/#{units_directory_name}/#{file_name}"
|
|
40
|
+
to = "../../../../#{relative_unit_directory}/#{type}"
|
|
37
41
|
create_link(from, to)
|
|
38
42
|
end
|
|
39
43
|
|
|
40
|
-
def
|
|
44
|
+
def relative_unit_directory
|
|
45
|
+
Pathname.new(unit_directory).relative_path_from(Rails.root)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def unit_directory
|
|
41
49
|
"#{Chanko::Config.units_directory_path}/#{file_name}"
|
|
42
50
|
end
|
|
43
51
|
|
|
44
|
-
def
|
|
52
|
+
def units_directory_name
|
|
45
53
|
Chanko::Config.units_directory_path.split("/").last
|
|
46
54
|
end
|
|
47
55
|
end
|
|
48
56
|
end
|
|
49
57
|
end
|
|
58
|
+
|
|
@@ -6,10 +6,8 @@ module Chanko
|
|
|
6
6
|
Loader.load(:example_unit)
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
Class.new(ActionView::Base) do
|
|
11
|
-
include Chanko::Invoker
|
|
12
|
-
|
|
9
|
+
def action_view_instance
|
|
10
|
+
klass = Class.new(ActionView::Base.with_empty_template_cache) do
|
|
13
11
|
def current_unit
|
|
14
12
|
units.last
|
|
15
13
|
end
|
|
@@ -17,21 +15,12 @@ module Chanko
|
|
|
17
15
|
def units
|
|
18
16
|
@units ||= []
|
|
19
17
|
end
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
view_paths.first.to_s
|
|
23
|
-
end
|
|
24
|
-
end.new
|
|
18
|
+
end
|
|
19
|
+
klass.with_view_paths([], {}, nil)
|
|
25
20
|
end
|
|
26
21
|
|
|
27
|
-
let(:
|
|
28
|
-
|
|
29
|
-
include Chanko::Invoker
|
|
30
|
-
|
|
31
|
-
def units
|
|
32
|
-
@units ||= []
|
|
33
|
-
end
|
|
34
|
-
end.new
|
|
22
|
+
let(:context) do
|
|
23
|
+
action_view_instance
|
|
35
24
|
end
|
|
36
25
|
|
|
37
26
|
let(:options) do
|
|
@@ -42,19 +31,6 @@ module Chanko
|
|
|
42
31
|
it "invokes block with given context and stacked unit" do
|
|
43
32
|
expect(described_class.new(unit, :label) { current_unit }.invoke(context, options)).to eq(unit)
|
|
44
33
|
end
|
|
45
|
-
|
|
46
|
-
context "when context is a view" do
|
|
47
|
-
it "invokes with unit's view path" do
|
|
48
|
-
expect(described_class.new(unit, :label) { path }.invoke(context, options)).to eq(unit.view_path)
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
context "when context does not have view_paths" do
|
|
53
|
-
it "invokes successfully" do
|
|
54
|
-
expect(described_class.new(unit, :label) { "test" }.
|
|
55
|
-
invoke(context_without_view_paths, options)).to eq("test")
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
34
|
end
|
|
59
35
|
end
|
|
60
36
|
end
|
data/spec/chanko/invoker_spec.rb
CHANGED
|
@@ -3,19 +3,11 @@ require "spec_helper"
|
|
|
3
3
|
module Chanko
|
|
4
4
|
describe Invoker do
|
|
5
5
|
let(:view) do
|
|
6
|
-
|
|
7
|
-
include Chanko::Invoker
|
|
8
|
-
include Chanko::Helper
|
|
9
|
-
include Chanko::UnitProxyProvider
|
|
10
|
-
end.new
|
|
6
|
+
controller.helpers
|
|
11
7
|
end
|
|
12
8
|
|
|
13
9
|
let(:controller) do
|
|
14
|
-
Class.new(ActionController::Base)
|
|
15
|
-
include Chanko::Invoker
|
|
16
|
-
include Chanko::Helper
|
|
17
|
-
include Chanko::UnitProxyProvider
|
|
18
|
-
end.new
|
|
10
|
+
Class.new(ActionController::Base).new
|
|
19
11
|
end
|
|
20
12
|
|
|
21
13
|
describe "#invoke" do
|
data/spec/chanko/loader_spec.rb
CHANGED
|
@@ -4,38 +4,40 @@ module Chanko
|
|
|
4
4
|
describe Loader do
|
|
5
5
|
describe ".load" do
|
|
6
6
|
after do
|
|
7
|
-
|
|
7
|
+
Chanko::Loader.cache.clear
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
context "when existent unit name is passed" do
|
|
11
11
|
it "loads unit in units directory and returns the Module" do
|
|
12
|
-
expect(
|
|
12
|
+
expect(Chanko::Loader.load(:example_unit)).to eq(ExampleUnit)
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
context "when non-existent unit name is passed" do
|
|
17
17
|
it "returns nil" do
|
|
18
|
-
expect(
|
|
18
|
+
expect(Chanko::Loader.load(:non_existent_unit)).to eq(false)
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
context "when loader has ever loaded specified unit" do
|
|
23
|
-
it "load unit from cache" do
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
it "load unit from cache", classic: true do
|
|
24
|
+
expect(Chanko::Loader::ClassicLoader).to receive(:load_from_cache).twice.and_call_original
|
|
25
|
+
expect(Chanko::Loader::ClassicLoader).to receive(:save_to_cache).with(anything, ExampleUnit).and_call_original
|
|
26
|
+
expect(Chanko::Loader.load(:example_unit)).to eq(ExampleUnit)
|
|
27
|
+
expect(Chanko::Loader.load(:example_unit)).to eq(ExampleUnit)
|
|
27
28
|
end
|
|
28
29
|
end
|
|
29
30
|
|
|
30
31
|
context "when loader has ever loaded specified wrong unit" do
|
|
31
32
|
before do
|
|
32
|
-
|
|
33
|
+
Chanko::Loader.cache.clear
|
|
33
34
|
end
|
|
34
35
|
|
|
35
|
-
it "load unit from cache" do
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
it "load unit from cache", classic: true do
|
|
37
|
+
expect(Chanko::Loader::ClassicLoader).to receive(:load_from_cache).twice.and_call_original
|
|
38
|
+
expect(Chanko::Loader::ClassicLoader).to receive(:save_to_cache).with(anything, false).and_call_original
|
|
39
|
+
expect(Chanko::Loader.load(:non_existent_unit)).to eq(false)
|
|
40
|
+
expect(Chanko::Loader.load(:non_existent_unit)).to eq(false)
|
|
39
41
|
end
|
|
40
42
|
end
|
|
41
43
|
end
|
data/spec/chanko/test_spec.rb
CHANGED
|
@@ -4,11 +4,8 @@ require "chanko/test"
|
|
|
4
4
|
module Chanko
|
|
5
5
|
describe Test do
|
|
6
6
|
let(:view) do
|
|
7
|
-
Class.new(ActionView::Base)
|
|
8
|
-
|
|
9
|
-
include Chanko::Helper
|
|
10
|
-
include Chanko::UnitProxyProvider
|
|
11
|
-
end.new
|
|
7
|
+
klass = Class.new(ActionView::Base.with_empty_template_cache)
|
|
8
|
+
klass.with_view_paths(nil, {}, nil)
|
|
12
9
|
end
|
|
13
10
|
|
|
14
11
|
describe "#enable_unit" do
|
data/spec/chanko/unit_spec.rb
CHANGED
|
@@ -188,68 +188,5 @@ module Chanko
|
|
|
188
188
|
expect(view.__example_unit_test).to eq("test")
|
|
189
189
|
end
|
|
190
190
|
end
|
|
191
|
-
|
|
192
|
-
describe ".models" do
|
|
193
|
-
before do
|
|
194
|
-
stub_const("ExampleModel", model_class)
|
|
195
|
-
unit.models do
|
|
196
|
-
expand(:ExampleModel) do
|
|
197
|
-
scope :active, lambda { where(:deleted_at => nil) }
|
|
198
|
-
|
|
199
|
-
has_one :user
|
|
200
|
-
|
|
201
|
-
def test
|
|
202
|
-
"test"
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
class_methods do
|
|
206
|
-
def test
|
|
207
|
-
"test"
|
|
208
|
-
end
|
|
209
|
-
end
|
|
210
|
-
end
|
|
211
|
-
end
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
let(:model_class) do
|
|
215
|
-
Class.new do
|
|
216
|
-
include UnitProxyProvider
|
|
217
|
-
|
|
218
|
-
def self.scope(name, *args)
|
|
219
|
-
singleton_class.class_eval do
|
|
220
|
-
define_method(name) { "scoped" }
|
|
221
|
-
end
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
def self.has_one(name, *args)
|
|
225
|
-
singleton_class.class_eval do
|
|
226
|
-
define_method(name) { args }
|
|
227
|
-
end
|
|
228
|
-
end
|
|
229
|
-
end
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
it "defines instance methods with prefix" do
|
|
233
|
-
expect(ExampleModel.new.__example_unit_test).to eq("test")
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
it "defines class methods with prefix" do
|
|
237
|
-
expect(ExampleModel.__example_unit_test).to eq("test")
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
it "defines scope method with prefix" do
|
|
241
|
-
expect(ExampleModel.__example_unit_active).to eq("scoped")
|
|
242
|
-
end
|
|
243
|
-
|
|
244
|
-
it "defines has_one association method with prefix" do
|
|
245
|
-
expect(ExampleModel.__example_unit_user).to eq([:class_name => "User"])
|
|
246
|
-
end
|
|
247
|
-
end
|
|
248
|
-
|
|
249
|
-
describe ".view_path" do
|
|
250
|
-
it "returns path for its view directory" do
|
|
251
|
-
expect(unit.view_path).to eq("#{Config.units_directory_path}/example_unit/views")
|
|
252
|
-
end
|
|
253
|
-
end
|
|
254
191
|
end
|
|
255
192
|
end
|
|
@@ -19,22 +19,6 @@ module EntryDeletion
|
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
models do
|
|
23
|
-
expand(:Entry) do
|
|
24
|
-
scope :active, lambda { where(:deleted_at => nil) }
|
|
25
|
-
|
|
26
|
-
def soft_delete
|
|
27
|
-
update_attributes(:deleted_at => Time.now)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
class_methods do
|
|
31
|
-
def gc_all_soft_deleted_users
|
|
32
|
-
where.not(deleted_at: nil).delete_all
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
22
|
helpers do
|
|
39
23
|
def link_to_deletion(entry)
|
|
40
24
|
link_to "Delete", entry, :method => :delete
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
../../../../fixtures/units/example_unit/views
|
|
@@ -47,7 +47,15 @@ module Dummy
|
|
|
47
47
|
# config.active_record.schema_format = :sql
|
|
48
48
|
|
|
49
49
|
# Version of your assets, change this if you want to expire all your assets
|
|
50
|
-
|
|
50
|
+
|
|
51
|
+
# for Rails 6.1
|
|
52
|
+
if config.respond_to?("assets")
|
|
53
|
+
config.assets.version = '1.0'
|
|
54
|
+
config.assets.quiet = true
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
config.autoloader = :zeitwerk
|
|
51
58
|
end
|
|
52
59
|
end
|
|
53
60
|
|
|
61
|
+
Rails.autoloaders.main.collapse(Rails.root.join('app', 'units', '*'))
|
data/spec/dummy/config/boot.rb
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
require 'rubygems'
|
|
2
|
-
gemfile = File.expand_path('../../../../Gemfile', __FILE__)
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
require 'bundler'
|
|
7
|
-
Bundler.setup
|
|
3
|
+
unless ENV['BUNDLE_GEMFILE']
|
|
4
|
+
raise "Select Gemfile_x.rb from gemfiles dir then set BUNDLE_GEMFILE"
|
|
8
5
|
end
|
|
9
6
|
|
|
7
|
+
require 'bundler/setup'
|
|
8
|
+
|
|
10
9
|
$:.unshift File.expand_path('../../../../lib', __FILE__)
|
|
@@ -29,5 +29,12 @@ Dummy::Application.configure do
|
|
|
29
29
|
# Print deprecation notices to the stderr
|
|
30
30
|
config.active_support.deprecation = :stderr
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
if ENV['EAGER_LOAD'] == 'true'
|
|
33
|
+
Chanko::Test.logger.info("EagerLoad: on")
|
|
34
|
+
config.eager_load = true
|
|
35
|
+
else
|
|
36
|
+
Chanko::Test.logger.info("EagerLoad: off")
|
|
37
|
+
config.eager_load = false
|
|
38
|
+
end
|
|
39
|
+
|
|
33
40
|
end
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -27,7 +27,7 @@ module ExampleUnit
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
function(:render) do
|
|
30
|
-
render_to_string :partial => "/test", :locals => { :local => "test" }
|
|
30
|
+
render_to_string :partial => "/units/example_unit/test", :locals => { :local => "test" }
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
function(:nesting_locals_outer) do
|
|
@@ -78,7 +78,7 @@ module ExampleUnit
|
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
function(:render) do
|
|
81
|
-
render "/test", :local => "test"
|
|
81
|
+
render "/units/example_unit/test", :local => "test"
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
function(:blank) do
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
|
-
require
|
|
2
|
-
|
|
1
|
+
require 'simplecov'
|
|
2
|
+
|
|
3
|
+
SimpleCov.start 'rails' do
|
|
4
|
+
if ENV['CI']
|
|
5
|
+
require 'simplecov-lcov'
|
|
6
|
+
SimpleCov::Formatter::LcovFormatter.config do |c|
|
|
7
|
+
c.report_with_single_file = true
|
|
8
|
+
c.single_report_path = 'coverage/lcov.info'
|
|
9
|
+
end
|
|
10
|
+
formatter SimpleCov::Formatter::LcovFormatter
|
|
11
|
+
end
|
|
3
12
|
|
|
4
|
-
require "simplecov"
|
|
5
|
-
SimpleCov.start do
|
|
6
13
|
add_filter "/spec\/fixtures/"
|
|
7
14
|
add_filter "/spec\/dummy/"
|
|
8
15
|
end
|
|
9
16
|
|
|
10
17
|
ENV["RAILS_ENV"] ||= "test"
|
|
11
18
|
require "chanko"
|
|
19
|
+
require "chanko/test"
|
|
20
|
+
Chanko::Config.units_directory_path = File.expand_path("../fixtures/units", __FILE__)
|
|
12
21
|
|
|
13
22
|
require File.expand_path("../dummy/config/environment", __FILE__)
|
|
14
23
|
require "rspec/rails"
|
|
@@ -38,6 +47,11 @@ RSpec.configure do |config|
|
|
|
38
47
|
# # Equivalent to being in spec/controllers
|
|
39
48
|
# end
|
|
40
49
|
config.infer_spec_type_from_file_location!
|
|
50
|
+
|
|
51
|
+
if Rails.respond_to?(:autoloaders) && Rails.autoloaders.zeitwerk_enabled?
|
|
52
|
+
config.filter_run_excluding classic: true
|
|
53
|
+
else
|
|
54
|
+
config.filter_run_excluding zeitwerk: true
|
|
55
|
+
end
|
|
41
56
|
end
|
|
42
57
|
|
|
43
|
-
Chanko::Config.units_directory_path = File.expand_path("../fixtures/units", __FILE__)
|