chanko 2.2.1 → 2.3.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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/master_and_pr.yml +64 -0
  3. data/CHANGELOG.md +7 -0
  4. data/README.md +2 -2
  5. data/bin/setup +8 -0
  6. data/bin/test +7 -0
  7. data/chanko.gemspec +4 -2
  8. data/gemfiles/Gemfile_rails_5.0.rb +6 -0
  9. data/gemfiles/Gemfile_rails_5.0.rb.lock +203 -0
  10. data/gemfiles/Gemfile_rails_5.1.rb +6 -0
  11. data/gemfiles/Gemfile_rails_5.1.rb.lock +203 -0
  12. data/gemfiles/Gemfile_rails_5.2.rb +6 -0
  13. data/gemfiles/Gemfile_rails_5.2.rb.lock +209 -0
  14. data/gemfiles/Gemfile_rails_6.0.rb +8 -0
  15. data/gemfiles/Gemfile_rails_6.0.rb.lock +238 -0
  16. data/gemfiles/Gemfile_rails_6.1.rb +8 -0
  17. data/gemfiles/Gemfile_rails_6.1.rb.lock +241 -0
  18. data/lib/chanko/config.rb +18 -4
  19. data/lib/chanko/loader.rb +124 -48
  20. data/lib/chanko/railtie.rb +16 -13
  21. data/lib/chanko/resolver/no_cache_file_system_resolver.rb +13 -0
  22. data/lib/chanko/test.rb +4 -0
  23. data/lib/chanko/version.rb +1 -1
  24. data/spec/chanko/function_spec.rb +30 -4
  25. data/spec/chanko/invoker_spec.rb +2 -10
  26. data/spec/chanko/loader_spec.rb +14 -12
  27. data/spec/chanko/test_spec.rb +15 -5
  28. data/spec/controllers/application_controller_spec.rb +1 -1
  29. data/spec/dummy/app/assets/config/manifest.js +3 -0
  30. data/spec/dummy/config/application.rb +13 -0
  31. data/spec/dummy/config/boot.rb +4 -5
  32. data/spec/dummy/config/environment.rb +1 -1
  33. data/spec/dummy/config/environments/test.rb +8 -1
  34. data/spec/dummy/config/initializers/chanko_initializer.rb +0 -0
  35. data/spec/dummy/config/storage.yml +1 -0
  36. data/spec/spec_helper.rb +19 -5
  37. metadata +58 -10
  38. data/.travis.yml +0 -8
  39. data/Gemfile +0 -11
data/lib/chanko/config.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'chanko/resolver/no_cache_file_system_resolver'
2
+
1
3
  module Chanko
2
4
  module Config
3
5
  class << self
@@ -6,13 +8,11 @@ module Chanko
6
8
  :backtrace_limit,
7
9
  :cache_units,
8
10
  :compatible_css_class,
9
- :eager_load,
10
11
  :enable_logger,
11
12
  :propagated_errors,
12
13
  :proxy_method_name,
13
14
  :raise_error,
14
15
  :resolver,
15
- :units_directory_path
16
16
  )
17
17
 
18
18
  def reset
@@ -20,13 +20,27 @@ module Chanko
20
20
  self.backtrace_limit = 10
21
21
  self.compatible_css_class = false
22
22
  self.enable_logger = true
23
- self.eager_load = Rails.env.production?
24
23
  self.propagated_errors = []
25
24
  self.proxy_method_name = :unit
26
25
  self.raise_error = Rails.env.development?
27
- self.resolver = Gem::Version.new(Rails::VERSION::STRING) >= Gem::Version.new('7') ? ActionView::FileSystemResolver : ActionView::OptimizedFileSystemResolver
26
+ self.resolver = resolver_for_using_rails_and_env
28
27
  self.units_directory_path = "app/units"
29
28
  end
29
+
30
+ def units_directory_path=(path)
31
+ @units_directory_path = path
32
+ end
33
+
34
+ def units_directory_path
35
+ @resolved_units_directory_path ||= Rails.root.join(@units_directory_path).to_s
36
+ end
37
+
38
+ def resolver_for_using_rails_and_env
39
+ return ActionView::FileSystemResolver if Rails::VERSION::MAJOR >= 7
40
+ return Chanko::Resolver::NoCacheFileSystemResolver if Rails.env.development?
41
+ return ActionView::OptimizedFileSystemResolver
42
+ end
43
+ private :resolver_for_using_rails_and_env
30
44
  end
31
45
 
32
46
  reset
data/lib/chanko/loader.rb CHANGED
@@ -1,73 +1,149 @@
1
1
  require "pathname"
2
-
3
2
  module Chanko
4
- class Loader
3
+ module Loader
4
+ class MissingEagarLoadSettingError < StandardError; end
5
+
5
6
  class << self
6
- def load(unit_name)
7
- new(unit_name).load
7
+ delegate :load, :cache, :eager_load_units!, to: "loader"
8
+ end
9
+
10
+ def self.loader
11
+ zeitwerk? ? ZeitwerkLoader : ClassicLoader
12
+ end
13
+
14
+ def self.zeitwerk?
15
+ Rails.respond_to?(:autoloaders) && Rails.autoloaders.zeitwerk_enabled?
16
+ end
17
+
18
+ def self.classic?
19
+ !zeitwerk?
20
+ end
21
+
22
+ def self.prepare_eager_load(mode: )
23
+ if mode == :zeitwerk && zeitwerk?
24
+ self.loader.prepare_eager_load
25
+ elsif mode == :classic && classic?
26
+ self.loader.prepare_eager_load
8
27
  end
28
+ end
9
29
 
10
- def cache
11
- @cache ||= {}
30
+ class ZeitwerkLoader
31
+ def self.load(name)
32
+ self.new(name).load
33
+ end
34
+
35
+ def self.cache
36
+ # backward compatibility
37
+ { }
38
+ end
39
+
40
+ def self.eager_load_units!
41
+ # Zeitwerk load chanko units as default
42
+ end
43
+
44
+ def self.prepare_eager_load
45
+ add_unit_directory_to_eager_load_paths
46
+ Rails.autoloaders.main.collapse(Chanko::Config.units_directory_path + '/*')
47
+ Rails.autoloaders.main.ignore(Chanko::Config.units_directory_path + '/*/spec*')
12
48
  end
13
49
 
14
- def eager_load_units!
15
- Pathname.glob("#{Rails.root}/#{Config.units_directory_path}/*").select(&:directory?).each do |path|
16
- load(path.to_s.split("/").last.to_sym) rescue nil
50
+ def self.add_unit_directory_to_eager_load_paths
51
+ path = Chanko::Config.units_directory_path
52
+
53
+ unless Rails.configuration.eager_load_paths.include?(path)
54
+ Rails.configuration.eager_load_paths << path
17
55
  end
18
56
  end
19
- end
20
57
 
21
- def initialize(name)
22
- @name = name
23
- end
58
+ def initialize(name)
59
+ @name = name
60
+ end
24
61
 
25
- def load
26
- if loaded?
27
- load_from_cache
28
- else
29
- load_from_file
62
+ def load
63
+ constantize
64
+ rescue NameError
65
+ # Chanko never raise error even if the constant fails to reference
66
+ false
30
67
  end
31
- end
32
68
 
33
- def loaded?
34
- cache[@name] != nil
69
+ def constantize
70
+ @name.to_s.camelize.constantize
71
+ end
35
72
  end
36
73
 
37
- def load_from_cache
38
- cache[@name]
39
- end
74
+ class ClassicLoader
75
+ def self.cache
76
+ @cache ||= {}
77
+ end
40
78
 
41
- def load_from_file
42
- add_autoload_path
43
- cache[@name] = constantize
44
- rescue Exception => exception
45
- ExceptionHandler.handle(exception)
46
- cache[@name] = false
47
- nil
48
- end
79
+ def self.eager_load_units!
80
+ Pathname.glob("#{Chanko::Config.units_directory_path}/*").select(&:directory?).each do |path|
81
+ Chanko::Loader::ClassicLoader.load(path.basename.to_s.to_sym)
82
+ end
83
+ end
49
84
 
50
- def add_autoload_path
51
- unless Rails.respond_to?(:autoloaders) && Rails.autoloaders.zeitwerk_enabled?
52
- ActiveSupport::Dependencies.autoload_paths << autoload_path
53
- ActiveSupport::Dependencies.autoload_paths.uniq!
85
+ def self.prepare_eager_load
86
+ raise MissingEagarLoadSettingError if Rails.configuration.eager_load.nil?
87
+
88
+ if Rails.configuration.eager_load
89
+ ruleout_unit_files_from_rails_eager_loading
90
+ end
54
91
  end
55
- end
56
92
 
57
- def autoload_path
58
- Rails.root.join("#{directory_path}/#@name").to_s
59
- end
93
+ def self.ruleout_unit_files_from_rails_eager_loading
94
+ Rails.configuration.eager_load_paths.delete(Chanko::Config.units_directory_path)
95
+ end
60
96
 
61
- def directory_path
62
- Config.units_directory_path
63
- end
97
+ def self.load(name)
98
+ self.new(name).load
99
+ end
64
100
 
65
- def constantize
66
- @name.to_s.camelize.constantize
67
- end
101
+ def self.load_from_cache(name)
102
+ self.cache[name]
103
+ end
104
+
105
+ def self.save_to_cache(name, unit)
106
+ self.cache[name] = unit
107
+ end
108
+
109
+ def initialize(name)
110
+ @name = name
111
+ end
68
112
 
69
- def cache
70
- self.class.cache
113
+ def load
114
+ load_from_cache.then do |unit|
115
+ next unit unless unit.nil?
116
+ load_from_file_and_store_to_cache
117
+ end
118
+ end
119
+
120
+ def load_from_file_and_store_to_cache
121
+ add_autoload_path
122
+ constantize.tap do |unit|
123
+ self.class.save_to_cache(@name, unit)
124
+ end
125
+ rescue Exception => exception
126
+ ExceptionHandler.handle(exception)
127
+ self.class.save_to_cache(@name, false)
128
+ false
129
+ end
130
+
131
+ def load_from_cache
132
+ self.class.load_from_cache(@name)
133
+ end
134
+
135
+ def add_autoload_path
136
+ ActiveSupport::Dependencies.autoload_paths << autoload_path
137
+ ActiveSupport::Dependencies.autoload_paths.uniq!
138
+ end
139
+
140
+ def autoload_path
141
+ "#{Config.units_directory_path }/#{@name}"
142
+ end
143
+
144
+ def constantize
145
+ @name.to_s.camelize.constantize
146
+ end
71
147
  end
72
148
  end
73
149
  end
@@ -1,6 +1,6 @@
1
1
  module Chanko
2
2
  class Railtie < Rails::Railtie
3
- initializer "chanko" do |app|
3
+ initializer "chanko.include", before: :eager_load! do |app|
4
4
  ActiveSupport.on_load :action_view do
5
5
  ::ActionView::Base.send(:include, Helper, Invoker, UnitProxyProvider)
6
6
  end
@@ -14,22 +14,25 @@ module Chanko
14
14
  end
15
15
  end
16
16
 
17
- initializer("chanko.support_zeitwerk") do |app|
18
- if Rails.respond_to?(:autoloaders) && Rails.autoloaders.zeitwerk_enabled?
19
- Rails.autoloaders.main.collapse(Rails.root.join(Chanko::Config.units_directory_path, '*'))
20
- end
17
+
18
+ initializer("chanko.zeitwerk.prepare_eager_load", before: :set_autoload_paths) do |app|
19
+ # zeitwerk freezes autoload_paths after :set_autoload_paths.
20
+ # So we need to prepare before set_autoload_paths
21
+ Chanko::Loader.prepare_eager_load(mode: :zeitwerk)
21
22
  end
22
23
 
23
- initializer("chanko.prevent_units_directory_from_eager_loading", before: :set_autoload_paths) do |app|
24
- if Chanko::Config.eager_load
25
- Rails.configuration.eager_load_paths.delete(Rails.root.join(Chanko::Config.units_directory_path).to_s)
26
- end
24
+ initializer("chanko.classic.prepare_eager_load", after: :load_environment_config) do |app|
25
+ # Rails5 doens't load environments/*.rb files before :set_autoload_paths.
26
+ # In other words, at this stage, config.eager_load cannot be determined to be true or false.
27
+ # But classic loader does not freeze paths on :set_autoload_paths.
28
+ # After all, It's ok if it is executed after :set_autoload_paths on Rails5 and Rails6(classic).
29
+ Chanko::Loader.prepare_eager_load(mode: :classic)
27
30
  end
28
31
 
29
- initializer("chanko.eager_load_units") do |app|
30
- if Chanko::Config.eager_load
31
- Chanko::Loader.eager_load_units!
32
- end
32
+ initializer("chanko.eager_load_units", before: :eager_load!) do |app|
33
+ # This is why we need handmade eager-loading
34
+ # https://github.com/cookpad/chanko/pull/38
35
+ Chanko::Loader.eager_load_units!
33
36
  end
34
37
  end
35
38
  end
@@ -0,0 +1,13 @@
1
+ unless defined?(ActionView::FileSystemResolver)
2
+ require 'action_view/template/resolver'
3
+ end
4
+
5
+ module Chanko
6
+ module Resolver
7
+ class NoCacheFileSystemResolver < ActionView::FileSystemResolver
8
+ def query(path, details, formats, locals, cache:)
9
+ super(path, details, formats, locals, cache: false)
10
+ end
11
+ end
12
+ end
13
+ end
data/lib/chanko/test.rb CHANGED
@@ -8,6 +8,10 @@ module Chanko
8
8
  def included(base)
9
9
  base.send :include, UnitProxyProvider
10
10
  end
11
+
12
+ def logger
13
+ @logger = ::Logger.new(STDOUT)
14
+ end
11
15
  end
12
16
 
13
17
  def enable_unit(unit_name)
@@ -1,3 +1,3 @@
1
1
  module Chanko
2
- VERSION = "2.2.1"
2
+ VERSION = "2.3.0"
3
3
  end
@@ -6,10 +6,25 @@ module Chanko
6
6
  Loader.load(:example_unit)
7
7
  end
8
8
 
9
- let(:context) do
10
- Class.new(ActionView::Base) do
11
- include Chanko::Invoker
9
+ def rails5_action_view_instance
10
+ klass = Class.new(ActionView::Base) do
11
+ def current_unit
12
+ units.last
13
+ end
14
+
15
+ def units
16
+ @units ||= []
17
+ end
18
+
19
+ def path
20
+ view_paths.first.to_s
21
+ end
22
+ end
23
+ klass.new
24
+ end
12
25
 
26
+ def rails6_action_view_instance
27
+ klass = Class.new(ActionView::Base.with_empty_template_cache) do
13
28
  def current_unit
14
29
  units.last
15
30
  end
@@ -21,7 +36,18 @@ module Chanko
21
36
  def path
22
37
  view_paths.first.to_s
23
38
  end
24
- end.new
39
+ end
40
+
41
+ klass.with_view_paths([], {}, nil)
42
+ end
43
+
44
+ let(:context) do
45
+ case Rails::VERSION::MAJOR
46
+ when 5
47
+ rails5_action_view_instance
48
+ when 6
49
+ rails6_action_view_instance
50
+ end
25
51
  end
26
52
 
27
53
  let(:context_without_view_paths) do
@@ -3,19 +3,11 @@ require "spec_helper"
3
3
  module Chanko
4
4
  describe Invoker do
5
5
  let(:view) do
6
- Class.new(ActionView::Base) do
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) do
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
@@ -4,38 +4,40 @@ module Chanko
4
4
  describe Loader do
5
5
  describe ".load" do
6
6
  after do
7
- described_class.cache.clear
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(described_class.load(:example_unit)).to eq(ExampleUnit)
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(described_class.load(:non_existent_unit)).to eq(nil)
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
- expect_any_instance_of(described_class).to receive(:load_from_file).and_call_original
25
- described_class.load(:example_unit)
26
- described_class.load(:example_unit)
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
- described_class.cache.clear
33
+ Chanko::Loader.cache.clear
33
34
  end
34
35
 
35
- it "load unit from cache" do
36
- expect_any_instance_of(described_class).to receive(:load_from_file).and_call_original
37
- described_class.load(:non_existent_unit)
38
- described_class.load(:non_existent_unit)
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
@@ -3,12 +3,22 @@ require "chanko/test"
3
3
 
4
4
  module Chanko
5
5
  describe Test do
6
+ def rails5_action_view_instance
7
+ Class.new(ActionView::Base).new
8
+ end
9
+
10
+ def rails6_action_view_instance
11
+ klass = Class.new(ActionView::Base.with_empty_template_cache)
12
+ klass.with_view_paths(nil, {}, nil)
13
+ end
14
+
6
15
  let(:view) do
7
- Class.new(ActionView::Base) do
8
- include Chanko::Invoker
9
- include Chanko::Helper
10
- include Chanko::UnitProxyProvider
11
- end.new
16
+ case Rails::VERSION::MAJOR
17
+ when 5
18
+ rails5_action_view_instance
19
+ when 6
20
+ rails6_action_view_instance
21
+ end
12
22
  end
13
23
 
14
24
  describe "#enable_unit" do
@@ -7,7 +7,7 @@ describe ApplicationController do
7
7
  end
8
8
  end
9
9
 
10
- it "clears cache before each request" do
10
+ it "clears cache before each request", classic: true do
11
11
  expect(Chanko::Loader.cache).to receive(:clear).exactly(2)
12
12
  get :index
13
13
  get :index
@@ -0,0 +1,3 @@
1
+ //= link_tree ../images
2
+ //= link_directory ../javascripts .js
3
+ //= link_directory ../stylesheets .css
@@ -48,6 +48,19 @@ module Dummy
48
48
 
49
49
  # Version of your assets, change this if you want to expire all your assets
50
50
  config.assets.version = '1.0'
51
+ config.assets.quiet = true if ::Rails::VERSION::MAJOR >= 5
52
+ if Rails::VERSION::MAJOR >= 6
53
+ if ENV['AUTOLOADER'] == 'zeitwerk'
54
+ Chanko::Test.logger.info("Autoloader: zeitwerk")
55
+ config.autoloader = :zeitwerk
56
+ else
57
+ Chanko::Test.logger.info("Autoloader: classic")
58
+ config.autoloader = :classic
59
+ end
60
+ end
51
61
  end
52
62
  end
53
63
 
64
+ if Rails::VERSION::MAJOR >= 6 && Rails.autoloaders.zeitwerk_enabled?
65
+ Rails.autoloaders.main.collapse(Rails.root.join('app', 'units', '*'))
66
+ end
@@ -1,10 +1,9 @@
1
1
  require 'rubygems'
2
- gemfile = File.expand_path('../../../../Gemfile', __FILE__)
3
2
 
4
- if File.exist?(gemfile)
5
- ENV['BUNDLE_GEMFILE'] = gemfile
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__)
@@ -2,4 +2,4 @@
2
2
  require File.expand_path('../application', __FILE__)
3
3
 
4
4
  # Initialize the rails application
5
- Dummy::Application.initialize!
5
+ Rails.application.initialize!
@@ -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
- config.eager_load = false
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
@@ -0,0 +1 @@
1
+
data/spec/spec_helper.rb CHANGED
@@ -1,14 +1,23 @@
1
- require "coveralls"
2
- Coveralls.wear!
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__)