chanko 2.2.1 → 2.3.0

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