assets-publisher-for-hanami 2.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.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +13 -0
  5. data/Gemfile +7 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +257 -0
  8. data/Rakefile +2 -0
  9. data/assets-publisher-for-hanami.gemspec +33 -0
  10. data/bin/setup +7 -0
  11. data/lib/cabeza-de-termo/assets-publisher/assets/asset.rb +81 -0
  12. data/lib/cabeza-de-termo/assets-publisher/assets/types/asset-type.rb +41 -0
  13. data/lib/cabeza-de-termo/assets-publisher/assets/types/javascript-type.rb +20 -0
  14. data/lib/cabeza-de-termo/assets-publisher/assets/types/stylesheet-type.rb +20 -0
  15. data/lib/cabeza-de-termo/assets-publisher/clock-cards/clock-card-machine.rb +43 -0
  16. data/lib/cabeza-de-termo/assets-publisher/clock-cards/clock-card.rb +47 -0
  17. data/lib/cabeza-de-termo/assets-publisher/compilation-jobs/compilation-job.rb +80 -0
  18. data/lib/cabeza-de-termo/assets-publisher/compilation-jobs/compilation-jobs-builder.rb +52 -0
  19. data/lib/cabeza-de-termo/assets-publisher/compilation-jobs/one-file-per-asset-builder.rb +66 -0
  20. data/lib/cabeza-de-termo/assets-publisher/compilers/command-line-compiler.rb +26 -0
  21. data/lib/cabeza-de-termo/assets-publisher/compilers/compiler.rb +50 -0
  22. data/lib/cabeza-de-termo/assets-publisher/compilers/tilt-compiler.rb +47 -0
  23. data/lib/cabeza-de-termo/assets-publisher/configuration/configuration.rb +66 -0
  24. data/lib/cabeza-de-termo/assets-publisher/errors/asset-not-found-error.rb +12 -0
  25. data/lib/cabeza-de-termo/assets-publisher/errors/compilation-job-failed-error.rb +14 -0
  26. data/lib/cabeza-de-termo/assets-publisher/errors/compilation-job-not-supported-error.rb +14 -0
  27. data/lib/cabeza-de-termo/assets-publisher/errors/error.rb +6 -0
  28. data/lib/cabeza-de-termo/assets-publisher/errors/unknown-asset-location-error.rb +12 -0
  29. data/lib/cabeza-de-termo/assets-publisher/helpers/helper.rb +27 -0
  30. data/lib/cabeza-de-termo/assets-publisher/locations/absolute-location.rb +25 -0
  31. data/lib/cabeza-de-termo/assets-publisher/locations/location.rb +54 -0
  32. data/lib/cabeza-de-termo/assets-publisher/locations/source-location.rb +13 -0
  33. data/lib/cabeza-de-termo/assets-publisher/publisher.rb +142 -0
  34. data/lib/cabeza-de-termo/assets-publisher/source-finders/assets-finder.rb +44 -0
  35. data/lib/cabeza-de-termo/assets-publisher/source-finders/assets-source.rb +31 -0
  36. data/lib/cabeza-de-termo/assets-publisher/version.rb +7 -0
  37. 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,12 @@
1
+ require_relative 'error'
2
+
3
+ module CabezaDeTermo
4
+ module AssetsPublisher
5
+ class AssetNotFoundError < Error
6
+ def initialize(asset_uri)
7
+ super("The asset '#{asset_uri}' was not found.")
8
+ @asset_uri = asset_uri
9
+ end
10
+ end
11
+ end
12
+ 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,6 @@
1
+ module CabezaDeTermo
2
+ module AssetsPublisher
3
+ class Error < ::StandardError
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,12 @@
1
+ require_relative 'error'
2
+
3
+ module CabezaDeTermo
4
+ module AssetsPublisher
5
+ class UnknownAssetLocationError < Error
6
+ def initialize(asset_uri)
7
+ super("Unkown location for '#{asset_uri}'.")
8
+ @asset_uri = asset_uri
9
+ end
10
+ end
11
+ end
12
+ 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