assets-publisher-for-hanami 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +7 -0
- data/.rspec +1 -0
- data/.travis.yml +13 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +257 -0
- data/Rakefile +2 -0
- data/assets-publisher-for-hanami.gemspec +33 -0
- data/bin/setup +7 -0
- data/lib/cabeza-de-termo/assets-publisher/assets/asset.rb +81 -0
- data/lib/cabeza-de-termo/assets-publisher/assets/types/asset-type.rb +41 -0
- data/lib/cabeza-de-termo/assets-publisher/assets/types/javascript-type.rb +20 -0
- data/lib/cabeza-de-termo/assets-publisher/assets/types/stylesheet-type.rb +20 -0
- data/lib/cabeza-de-termo/assets-publisher/clock-cards/clock-card-machine.rb +43 -0
- data/lib/cabeza-de-termo/assets-publisher/clock-cards/clock-card.rb +47 -0
- data/lib/cabeza-de-termo/assets-publisher/compilation-jobs/compilation-job.rb +80 -0
- data/lib/cabeza-de-termo/assets-publisher/compilation-jobs/compilation-jobs-builder.rb +52 -0
- data/lib/cabeza-de-termo/assets-publisher/compilation-jobs/one-file-per-asset-builder.rb +66 -0
- data/lib/cabeza-de-termo/assets-publisher/compilers/command-line-compiler.rb +26 -0
- data/lib/cabeza-de-termo/assets-publisher/compilers/compiler.rb +50 -0
- data/lib/cabeza-de-termo/assets-publisher/compilers/tilt-compiler.rb +47 -0
- data/lib/cabeza-de-termo/assets-publisher/configuration/configuration.rb +66 -0
- data/lib/cabeza-de-termo/assets-publisher/errors/asset-not-found-error.rb +12 -0
- data/lib/cabeza-de-termo/assets-publisher/errors/compilation-job-failed-error.rb +14 -0
- data/lib/cabeza-de-termo/assets-publisher/errors/compilation-job-not-supported-error.rb +14 -0
- data/lib/cabeza-de-termo/assets-publisher/errors/error.rb +6 -0
- data/lib/cabeza-de-termo/assets-publisher/errors/unknown-asset-location-error.rb +12 -0
- data/lib/cabeza-de-termo/assets-publisher/helpers/helper.rb +27 -0
- data/lib/cabeza-de-termo/assets-publisher/locations/absolute-location.rb +25 -0
- data/lib/cabeza-de-termo/assets-publisher/locations/location.rb +54 -0
- data/lib/cabeza-de-termo/assets-publisher/locations/source-location.rb +13 -0
- data/lib/cabeza-de-termo/assets-publisher/publisher.rb +142 -0
- data/lib/cabeza-de-termo/assets-publisher/source-finders/assets-finder.rb +44 -0
- data/lib/cabeza-de-termo/assets-publisher/source-finders/assets-source.rb +31 -0
- data/lib/cabeza-de-termo/assets-publisher/version.rb +7 -0
- metadata +191 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'tilt'
|
3
|
+
require_relative 'compiler'
|
4
|
+
|
5
|
+
module CabezaDeTermo
|
6
|
+
module AssetsPublisher
|
7
|
+
class TiltCompiler < Compiler
|
8
|
+
protected
|
9
|
+
|
10
|
+
def source_asset
|
11
|
+
compilation_job.assets.first
|
12
|
+
end
|
13
|
+
|
14
|
+
def compile_assets()
|
15
|
+
validate_assets_collection
|
16
|
+
|
17
|
+
compile_single_asset
|
18
|
+
end
|
19
|
+
|
20
|
+
def compile_single_asset()
|
21
|
+
just_copy? ? copy! : compile!
|
22
|
+
end
|
23
|
+
|
24
|
+
def validate_assets_collection()
|
25
|
+
raise_compilation_job_not_supported_error unless source_assets.size == 1
|
26
|
+
end
|
27
|
+
|
28
|
+
def just_copy?()
|
29
|
+
['.css', '.js'].include?(source_asset.real_path.extname)
|
30
|
+
end
|
31
|
+
|
32
|
+
def copy!()
|
33
|
+
::FileUtils.copy_file(source_asset.real_path, compilation_job.destination_filename)
|
34
|
+
end
|
35
|
+
|
36
|
+
def compile!()
|
37
|
+
::File.open(compilation_job.destination_filename, 'w') do |file|
|
38
|
+
file.write( render_source )
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def render_source()
|
43
|
+
Tilt.new(source_asset.real_path).render
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module CabezaDeTermo
|
2
|
+
module AssetsPublisher
|
3
|
+
# The Publisher configuration.
|
4
|
+
class Configuration
|
5
|
+
# Initialize the instance
|
6
|
+
def initialize
|
7
|
+
@source_folders = []
|
8
|
+
|
9
|
+
destination_folder nil
|
10
|
+
add_timestamps_to_published_assets true
|
11
|
+
stylesheets_compiler {}
|
12
|
+
javascripts_compiler {}
|
13
|
+
use_rendering_scope_assets_collector nil
|
14
|
+
end
|
15
|
+
|
16
|
+
# Answer if the Publisher will add a timestamp to the assets with relative paths
|
17
|
+
def add_timestamps_to_published_assets?
|
18
|
+
@add_timestamps_to_published_assets
|
19
|
+
end
|
20
|
+
|
21
|
+
# Set if the Publisher will add a timestamp to the assets with relative paths
|
22
|
+
def add_timestamps_to_published_assets(boolean)
|
23
|
+
@add_timestamps_to_published_assets = boolean
|
24
|
+
end
|
25
|
+
|
26
|
+
# Answer the asset sources collection
|
27
|
+
def source_folders
|
28
|
+
@source_folders
|
29
|
+
end
|
30
|
+
|
31
|
+
def destination_folder(folder)
|
32
|
+
@destination_folder = folder
|
33
|
+
end
|
34
|
+
|
35
|
+
def destination_path
|
36
|
+
::Pathname.new(@destination_folder)
|
37
|
+
end
|
38
|
+
|
39
|
+
def published_assets_subfolder
|
40
|
+
::Pathname.new('assets')
|
41
|
+
end
|
42
|
+
|
43
|
+
def stylesheets_compiler(&block)
|
44
|
+
return @stylesheets_compiler_block.call if block.nil?
|
45
|
+
@stylesheets_compiler_block = block
|
46
|
+
end
|
47
|
+
|
48
|
+
def javascripts_compiler(&block)
|
49
|
+
return @javascripts_compiler_block.call if block.nil?
|
50
|
+
@javascripts_compiler_block = block
|
51
|
+
end
|
52
|
+
|
53
|
+
def command_line_compiler(&block)
|
54
|
+
CommandLineCompiler.new(&block)
|
55
|
+
end
|
56
|
+
|
57
|
+
def use_rendering_scope_assets_collector(rendering_scope_assets_collector)
|
58
|
+
@rendering_scope_assets_collector = rendering_scope_assets_collector
|
59
|
+
end
|
60
|
+
|
61
|
+
def rendering_scope_assets_collector()
|
62
|
+
@rendering_scope_assets_collector
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative 'error'
|
2
|
+
|
3
|
+
module CabezaDeTermo
|
4
|
+
module AssetsPublisher
|
5
|
+
class CompilationJobFailedError < Error
|
6
|
+
def initialize(compiler, compilation_job, message)
|
7
|
+
super(message)
|
8
|
+
|
9
|
+
@compiler = compiler
|
10
|
+
@compilation_job = compilation_job
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative 'error'
|
2
|
+
|
3
|
+
module CabezaDeTermo
|
4
|
+
module AssetsPublisher
|
5
|
+
class CompilationJobNotSupportedError < Error
|
6
|
+
def initialize(compiler, compilation_job, message)
|
7
|
+
super(message)
|
8
|
+
|
9
|
+
@compiler = compiler
|
10
|
+
@compilation_job = compilation_job
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'cabeza-de-termo/assets-publisher/publisher'
|
2
|
+
|
3
|
+
module CabezaDeTermo
|
4
|
+
module AssetsPublisher
|
5
|
+
# The View helper.
|
6
|
+
# To use it, add this to your view:
|
7
|
+
#
|
8
|
+
# module Web
|
9
|
+
# module Views
|
10
|
+
# class YourView
|
11
|
+
# include CabezaDeTermo::AssetsPublisher::Helper
|
12
|
+
# ...
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# This will publish only one method to your views: #assets_publisher. From that method
|
18
|
+
# you can call the Publisher protocol.
|
19
|
+
module Helper
|
20
|
+
# Answer the Publisher to collect and publish stylesheets and javascripts from
|
21
|
+
# your current view.
|
22
|
+
def assets_publisher
|
23
|
+
Publisher.new
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative 'location'
|
2
|
+
|
3
|
+
module CabezaDeTermo
|
4
|
+
module AssetsPublisher
|
5
|
+
class AbsoluteLocation < Location
|
6
|
+
# Answer the path of the asset uri.
|
7
|
+
def real_path_of(uri)
|
8
|
+
Pathname.new(destination_path.to_s + uri.to_s).expand_path
|
9
|
+
end
|
10
|
+
|
11
|
+
# Asking
|
12
|
+
|
13
|
+
def is_absolute?()
|
14
|
+
true
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
# Answer the path of the folder where compiled assets are published
|
20
|
+
def destination_path
|
21
|
+
configuration.destination_path
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'cabeza-de-termo/assets-publisher/errors/unknown-asset-location-error'
|
2
|
+
|
3
|
+
module CabezaDeTermo
|
4
|
+
module AssetsPublisher
|
5
|
+
class Location
|
6
|
+
# Answer a new location for the uri
|
7
|
+
def self.from(uri)
|
8
|
+
class_for_uri(uri).new(uri)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Answer the class to use for the uri
|
12
|
+
def self.class_for_uri(uri)
|
13
|
+
uri = Pathname.new(uri)
|
14
|
+
|
15
|
+
return class_named("CabezaDeTermo::AssetsPublisher::AbsoluteLocation") if uri.absolute?
|
16
|
+
return class_named("CabezaDeTermo::AssetsPublisher::SourceLocation") if uri.relative?
|
17
|
+
|
18
|
+
raise UnknownAssetLocationError.new(uri)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Answer a class from its fully quilified name
|
22
|
+
def self.class_named(fully_qualified)
|
23
|
+
fully_qualified.split('::').inject(Object) do |mod, class_name|
|
24
|
+
mod.const_get(class_name)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Instance methods
|
29
|
+
|
30
|
+
def initialize(uri)
|
31
|
+
@uri = uri
|
32
|
+
end
|
33
|
+
|
34
|
+
# Answer the Publisher configuration.
|
35
|
+
def configuration
|
36
|
+
Publisher.configuration
|
37
|
+
end
|
38
|
+
|
39
|
+
# Asking
|
40
|
+
|
41
|
+
def is_absolute?()
|
42
|
+
false
|
43
|
+
end
|
44
|
+
|
45
|
+
# Answer the path of the asset uri
|
46
|
+
def real_path_of(uri)
|
47
|
+
CdT.subclass_responsibility
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
require_relative 'source-location'
|
54
|
+
require_relative 'absolute-location'
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative 'location'
|
2
|
+
require 'cabeza-de-termo/assets-publisher/source-finders/assets-finder'
|
3
|
+
|
4
|
+
module CabezaDeTermo
|
5
|
+
module AssetsPublisher
|
6
|
+
class SourceLocation < Location
|
7
|
+
# Answer the path of the asset uri
|
8
|
+
def real_path_of(uri)
|
9
|
+
(AssetsFinder.asset_source_path_of uri).expand_path
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'cdt/utilities/bind'
|
2
|
+
require 'cdt/utilities/subclass-responsibility'
|
3
|
+
require 'cdt/utilities/if-not-nil'
|
4
|
+
require_relative 'version'
|
5
|
+
require_relative 'configuration/configuration'
|
6
|
+
require_relative 'assets/asset'
|
7
|
+
require_relative 'compilation-jobs/one-file-per-asset-builder'
|
8
|
+
require_relative 'compilers/tilt-compiler'
|
9
|
+
require_relative 'compilers/command-line-compiler'
|
10
|
+
require_relative 'clock-cards/clock-card-machine'
|
11
|
+
|
12
|
+
module CabezaDeTermo
|
13
|
+
module AssetsPublisher
|
14
|
+
# The collector and publisher of the stylesheets and javascripts from the current view.
|
15
|
+
class Publisher
|
16
|
+
|
17
|
+
@configuration_prototype = nil
|
18
|
+
|
19
|
+
@clock_card_machine = ClockCardMachine.new
|
20
|
+
|
21
|
+
@configurations_per_thread = {}
|
22
|
+
|
23
|
+
# Class methods
|
24
|
+
class << self
|
25
|
+
# Answer the Publihser configuration
|
26
|
+
def configuration()
|
27
|
+
configurations_per_thread[::Thread.current]
|
28
|
+
end
|
29
|
+
|
30
|
+
# Pass the config to the block to allow the app to configure the Publisher
|
31
|
+
def configure(&block)
|
32
|
+
CdT.bind_block_evaluation_to configuration_prototype, &block
|
33
|
+
end
|
34
|
+
|
35
|
+
def clock_card_machine()
|
36
|
+
@clock_card_machine
|
37
|
+
end
|
38
|
+
|
39
|
+
def configurations_per_thread()
|
40
|
+
@configurations_per_thread
|
41
|
+
end
|
42
|
+
|
43
|
+
# Answer the Publihser configuration
|
44
|
+
def configuration_prototype()
|
45
|
+
@configuration_prototype ||= default_configuration
|
46
|
+
end
|
47
|
+
|
48
|
+
def reset_configuration_prototype()
|
49
|
+
@configuration_prototype = nil
|
50
|
+
end
|
51
|
+
|
52
|
+
def default_configuration()
|
53
|
+
CdT.bind_block_evaluation_to(Configuration.new) do
|
54
|
+
add_timestamps_to_published_assets true
|
55
|
+
|
56
|
+
stylesheets_compiler { TiltCompiler.new }
|
57
|
+
javascripts_compiler { TiltCompiler.new }
|
58
|
+
|
59
|
+
use_rendering_scope_assets_collector CabezaDeTermo::Assets::HanamiRenderingScope
|
60
|
+
|
61
|
+
self
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Instance methods
|
67
|
+
|
68
|
+
# Collect and publish the stylesheets from the rendering_scope. Answer the html to include
|
69
|
+
# in your template.
|
70
|
+
def stylesheets_for(rendering_scope)
|
71
|
+
with_configuration_copy do
|
72
|
+
compile_and_build_html_for(StylesheetType.new, rendering_scope)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Collect and publish the javascripts from the rendering_scope. Answer the html to include
|
77
|
+
# in your template.
|
78
|
+
def javascripts_for(rendering_scope)
|
79
|
+
with_configuration_copy do
|
80
|
+
compile_and_build_html_for(JavascriptType.new, rendering_scope)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
protected
|
85
|
+
|
86
|
+
def compile_and_build_html_for(asset_type, rendering_scope)
|
87
|
+
compile_assets_and_build_html_for asset_type, assets_for(asset_type, rendering_scope)
|
88
|
+
end
|
89
|
+
|
90
|
+
def compile_assets_and_build_html_for(asset_type, assets)
|
91
|
+
jobs = compilation_jobs_for(asset_type, assets)
|
92
|
+
|
93
|
+
compile_jobs(asset_type, jobs)
|
94
|
+
jobs_html(jobs)
|
95
|
+
end
|
96
|
+
|
97
|
+
def compile_jobs(asset_type, compilation_jobs)
|
98
|
+
compilation_jobs.each do |job|
|
99
|
+
compile(job, asset_type)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def compile(compilation_job, asset_type)
|
104
|
+
return unless clock_card_machine.is_outdated? compilation_job
|
105
|
+
|
106
|
+
compilation_job.compile_with(asset_type.compiler)
|
107
|
+
|
108
|
+
clock_card_machine.register_modifications_on compilation_job
|
109
|
+
end
|
110
|
+
|
111
|
+
def jobs_html(compilation_jobs)
|
112
|
+
compilation_jobs.inject('') do |html, compilation_job|
|
113
|
+
html += compilation_job.html
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Create and answer a new comopilation job
|
118
|
+
def compilation_jobs_for(asset_type, assets)
|
119
|
+
OneFilePerAssetBuilder.jobs_for asset_type, assets
|
120
|
+
end
|
121
|
+
|
122
|
+
def assets_for(asset_type, rendering_scope)
|
123
|
+
asset_type.collect_assets_from(rendering_scope)
|
124
|
+
end
|
125
|
+
|
126
|
+
def clock_card_machine()
|
127
|
+
self.class.clock_card_machine
|
128
|
+
end
|
129
|
+
|
130
|
+
def with_configuration_copy(&block)
|
131
|
+
begin
|
132
|
+
self.class.configurations_per_thread[::Thread.current] =
|
133
|
+
self.class.configuration_prototype.dup
|
134
|
+
|
135
|
+
block.call
|
136
|
+
ensure
|
137
|
+
self.class.configurations_per_thread.delete(::Thread.current)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|