gluey 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2fde00ea1efaad06ddc4780ae8cd89ba0608d2c3
4
+ data.tar.gz: d51d6124fbecf62a1bab250a7e8f62e0f9fda44d
5
+ SHA512:
6
+ metadata.gz: 8be79aa84654f1e3b1ce3f6e220cb8bd767eef34593503809c06d92ed01c7f024ce1ef2f9878cffc35bff50983557b562e8dcebd1f93822b808297a4a27c083b
7
+ data.tar.gz: 177013b823b9a1bd66aaa8773e5fc501df265ceef0550afb15547b3962288598a53a5feb1f0cd336e3419f38c5bd1c11045660c3e20e31655131b428c1f8bbba
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in gluey.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 doooby
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # Gluey
2
+
3
+ This is my custom alternative for processing assets in ruby web apps. Firt, there was just dislike in sprockets
4
+ (and their integration into rails), but then i realized it's not that big a deal to write my own caching and processing system.
5
+ This has unlimited abilities, because it's very easy to write custom directives (that headers in assets that you know from
6
+ sprockets). For example, you can precompile handlebars a nd insert them into page's js file as an object (it cannot be easier).
7
+ You can append, prepend, insert (...) other files, merge them into one asset, that you wanth to hit on
8
+ particular http path. There is no docs nor test for now, and probably never will be, but the code should not be hard
9
+ to read, so if you're interested, just digg into the code itself.
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ ```ruby
16
+ gem 'gluey'
17
+ ```
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install gluey
26
+
27
+ ## Usage
28
+
29
+ look at my nesselsburg2 integration (a repository just next door)
30
+
31
+ ## Contributing
32
+
33
+ 1. Fork it ( https://github.com/[my-github-username]/gluey/fork )
34
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
35
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
36
+ 4. Push to the branch (`git push origin my-new-feature`)
37
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
data/gluey.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'gluey/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'gluey'
7
+ spec.version = Gluey::VERSION
8
+ spec.authors = ['doooby']
9
+ spec.email = ['zelazk.o@email.cz']
10
+ spec.summary = 'Rails\' asset pipelane replacement'
11
+ spec.description = %q{Concatenating and processing asset files with possibly complicated dependencies.}
12
+ # spec.homepage = ""
13
+ spec.license = 'MIT'
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ # spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ # spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ['lib']
19
+
20
+ spec.add_development_dependency 'bundler', '~> 1.7'
21
+ spec.add_development_dependency 'rake', '~> 10.0'
22
+ end
@@ -0,0 +1,29 @@
1
+ require_relative 'single_file'
2
+
3
+ module Gluey::Dependencies
4
+ class Directory < SingleFile
5
+
6
+ def initialize(dir, dir_pattern=nil)
7
+ @dir_pattern = "#{dir}/#{ dir_pattern || '**/*' }"
8
+ super dir
9
+ end
10
+
11
+ def actualize
12
+ @files_list = files_list
13
+ super
14
+ end
15
+
16
+ def changed?
17
+ @files_list != files_list
18
+ end
19
+
20
+ def exists?
21
+ Dir.exists? @file
22
+ end
23
+
24
+ def files_list
25
+ Dir[@dir_pattern]
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,62 @@
1
+ require 'handlebars'
2
+ require_relative 'directory'
3
+
4
+ module Gluey::Dependencies
5
+ class Handlebars_bundle < SingleFile
6
+
7
+ def initialize(dir, logical_path, context)
8
+ tmp_dir = "#{context.tmp_path}/.texts_bundle"
9
+ Dir.mkdir tmp_dir unless Dir.exists? tmp_dir
10
+ @cache_path = "#{tmp_dir}/#{logical_path.gsub '/', '-'}"
11
+ Dir.mkdir @cache_path unless Dir.exists? @cache_path
12
+
13
+ @dir_dep = ::Gluey::Dependencies::Directory.new(dir, '**/*.hb')
14
+ @dependencies = []
15
+ super "#{@cache_path}.hb_bundle"
16
+ end
17
+
18
+ def changed?
19
+ @dependencies.any?{|d| d.changed?} || @dir_dep.changed? || (File.mtime(@file).to_i != @mtime rescue true)
20
+ end
21
+
22
+ def actualize
23
+ # remove deleted files
24
+ @dependencies.delete_if{|dep| !dep.exists? }
25
+ # add new files
26
+ new_files = (@dir_dep.files_list - @dependencies.map(&:file)).map do |f|
27
+ template = f[/#{@dir_dep.file}\/(.+)\.hb$/, 1]
28
+ ::Gluey::Dependencies::SingleFile.new f, template: template,
29
+ hb_precompiled: "#{@cache_path}/#{template.gsub '/', '-'}"
30
+ end
31
+ @dependencies.concat new_files
32
+ @dir_dep.actualize
33
+
34
+ # re-precompile changed
35
+ handlebars_context = ::Handlebars::Context.new
36
+ @dependencies.each do |dep|
37
+ next if !dep.changed? && File.exists?(dep.data[:hb_precompiled])
38
+ dep.actualize
39
+ precompile_output = handlebars_context.precompile File.read(dep.file)
40
+ File.write dep.data[:hb_precompiled], precompile_output
41
+ end
42
+
43
+ write_bundle
44
+ @mtime = File.mtime(@file).to_i
45
+ self
46
+ end
47
+
48
+ private
49
+
50
+ def write_bundle
51
+ File.open @file, 'w' do |f|
52
+ f.write '{'
53
+ @dependencies.each_with_index do |dep, i|
54
+ f.write "#{', ' if i!=0}\"#{dep.data[:template]}\": "
55
+ f.write File.read(dep.data[:hb_precompiled])
56
+ end
57
+ f.write '}'
58
+ end
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,29 @@
1
+ module Gluey::Dependencies
2
+ class SingleFile
3
+
4
+ attr_reader :file, :data
5
+
6
+ def initialize(file, **data)
7
+ @file = file
8
+ @data = data
9
+ end
10
+
11
+ def actualize
12
+ @mtime = File.mtime(@file).to_i
13
+ self
14
+ end
15
+
16
+ def changed?
17
+ File.mtime(@file).to_i != @mtime rescue true
18
+ end
19
+
20
+ def exists?
21
+ File.exists? @file
22
+ end
23
+
24
+ def ==(other)
25
+ @file == other.file
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,62 @@
1
+ require_relative 'directory'
2
+
3
+ module Gluey::Dependencies
4
+ class TextsBundle < SingleFile
5
+ JS_ESCAPE_MAP = {
6
+ '\\' => '\\\\',
7
+ "\r\n" => '\n',
8
+ "\n" => '\n',
9
+ "\r" => '\n',
10
+ '"' => '\\"',
11
+ "'" => "\\'"
12
+ }
13
+
14
+ def initialize(dir, logical_path, context)
15
+ tmp_dir = "#{context.tmp_path}/.texts_bundle"
16
+ Dir.mkdir tmp_dir unless Dir.exists? tmp_dir
17
+ @cache_path = "#{tmp_dir}/#{logical_path.gsub '/', '-'}"
18
+ Dir.mkdir @cache_path unless Dir.exists? @cache_path
19
+
20
+ @dir_dep = ::Gluey::Dependencies::Directory.new(dir, '**/*')
21
+ @dependencies = []
22
+ super "#{@cache_path}.texts_bundle"
23
+ end
24
+
25
+ def changed?
26
+ @dependencies.any?{|d| d.changed?} || @dir_dep.changed? || (File.mtime(@file).to_i != @mtime rescue true)
27
+ end
28
+
29
+ def actualize
30
+ # remove deleted files
31
+ @dependencies.delete_if{|dep| !dep.exists? }
32
+ # add new files
33
+ new_files = (@dir_dep.files_list - @dependencies.map(&:file)).map do |f|
34
+ text_name = f[/#{@dir_dep.file}\/(.+)$/, 1]
35
+ ::Gluey::Dependencies::SingleFile.new f, text_name: text_name
36
+ end
37
+ @dependencies.concat new_files
38
+ @dir_dep.actualize
39
+ @dependencies.each{|dep| dep.actualize if dep.changed? }
40
+
41
+ write_bundle
42
+ @mtime = File.mtime(@file).to_i
43
+ self
44
+ end
45
+
46
+ private
47
+
48
+ def write_bundle
49
+ File.open @file, 'w' do |f|
50
+ f.write '{'
51
+ @dependencies.each_with_index do |dep, i|
52
+ f.write "#{', ' if i!=0}\"#{dep.data[:text_name]}\": "
53
+ text = File.read dep.file
54
+ text.gsub!(/(\\|\r\n|[\n\r"'])/u){|match| JS_ESCAPE_MAP[match] }
55
+ f.write "\"#{text}\""
56
+ end
57
+ f.write '}'
58
+ end
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,4 @@
1
+ module Gluey
2
+ class FileNotFound < StandardError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Gluey
2
+ class ItemNotListed < StandardError
3
+ end
4
+ end
@@ -0,0 +1,25 @@
1
+ module Gluey::Glues
2
+ class Base
3
+
4
+ def initialize(context, material)
5
+ @context = context
6
+ @material = material
7
+ end
8
+
9
+ def process(base_file, dependecies)
10
+ read_base_file base_file
11
+ end
12
+
13
+ def read_base_file(file)
14
+ raw_content = File.read(file)
15
+ file[-4..-1]=='.erb' ? ERB.new(raw_content).result : raw_content
16
+ end
17
+
18
+ end
19
+
20
+ def self.load(name, *addons_names)
21
+ require_relative name
22
+ addons_names.flatten.each{|an| require_relative "#{name}/#{an}_addons" }
23
+ end
24
+
25
+ end
@@ -0,0 +1,24 @@
1
+ require_relative '../../dependencies/handlebars_bundle'
2
+
3
+ module Gluey::Glues
4
+ class JsScript < Script
5
+
6
+ def pre_replace_with_handlebars(args)
7
+ dir = File.expand_path("../#{args[1]}", @base_file)
8
+ raise "cannot find dir containing handlebars templates for script=#{@base_file}" unless dir && Dir.exists?(dir)
9
+
10
+ logical_path = dir[/(?:^#{@context.root_path}\/)?(.+)$/, 1]
11
+ key = "dep:hb_bundle:#{logical_path}:#{@material.name}"
12
+ hb_dep = @context.cache[key]
13
+ unless hb_dep
14
+ hb_dep = ::Gluey::Dependencies::Handlebars_bundle.new dir, logical_path, @context
15
+ @context.cache[key] = hb_dep
16
+ end
17
+
18
+ hb_dep.actualize if hb_dep.changed?
19
+ @dependencies << hb_dep
20
+ @script.gsub! /"%#{args[0]}%"/, File.read(hb_dep.file)
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,53 @@
1
+ require_relative 'script'
2
+ require_relative '../dependencies/texts_bundle'
3
+
4
+ module Gluey::Glues
5
+ class JsScript < Script
6
+
7
+ def post_strict(_)
8
+ @output = "'use strict';\n#{@output}"
9
+ end
10
+
11
+ def post_enclose(_)
12
+ @output = "(function(){\n#{@output}\n}());"
13
+ end
14
+
15
+ def post_strict_mode(_)
16
+ @output = "'use strict';\n#{@output}"
17
+ end
18
+
19
+ def pre_replace(args)
20
+ file = find_nested_file(args[1])
21
+ cached_file, deps = get_nested_piece file
22
+ @dependencies.concat deps
23
+ @script.gsub! /"%#{args[0]}%"/, File.read(cached_file)
24
+ end
25
+
26
+ def pre_return(args)
27
+ @script = "#{@script}\nreturn #{args.first};"
28
+ end
29
+
30
+ def post_return(_)
31
+ @output = "(function(){\n#{@output}\n}())"
32
+ end
33
+
34
+ end
35
+
36
+ def pre_replace_with_texts_bundle(args)
37
+ dir = File.expand_path("../#{args[1]}", @base_file)
38
+ raise "cannot find relative path #{args[1]} for script=#{@base_file}" unless dir && Dir.exists?(dir)
39
+
40
+ logical_path = dir[/(?:^#{@context.root_path}\/)?(.+)$/, 1]
41
+ key = "dep:txt_bundle:#{logical_path}:#{@material.name}"
42
+ hb_dep = @context.cache[key]
43
+ unless hb_dep
44
+ hb_dep = ::Gluey::Dependencies::TextsBundle.new dir, logical_path, @context
45
+ @context.cache[key] = hb_dep
46
+ end
47
+
48
+ hb_dep.actualize if hb_dep.changed?
49
+ @dependencies << hb_dep
50
+ @script.gsub! /"%#{args[0]}%"/, File.read(hb_dep.file)
51
+ end
52
+
53
+ end
@@ -0,0 +1,26 @@
1
+ require 'sass'
2
+ require_relative '../dependencies/single_file'
3
+
4
+ module Gluey::Glues
5
+ class Sass < Base
6
+
7
+ def process(base_file, deps)
8
+ opts = {
9
+ syntax: @material.file_extension.to_sym,
10
+ load_paths: [File.expand_path('..', base_file)],
11
+ cache_store: ::Sass::CacheStores::Filesystem.new("#{@context.tmp_path}/.sass"),
12
+ filename: base_file,
13
+ line_comments: true
14
+ }
15
+ engine = ::Sass::Engine.new(read_base_file(base_file), opts)
16
+ output = engine.render
17
+
18
+ engine.dependencies.each do |dependency|
19
+ deps << ::Gluey::Dependencies::SingleFile.new(dependency.options[:filename]).actualize
20
+ end
21
+
22
+ output
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,84 @@
1
+ require_relative '../dependencies/single_file'
2
+
3
+ module Gluey::Glues
4
+ class Script < Base
5
+
6
+ PREFIXES = ['//'].map{|p| Regexp.escape(p)}
7
+ DIRECTIVES_REGEXP = Regexp.compile "\\A(?:\\s*#{PREFIXES.map{|p| "(?:#{p}=.*\\n?)+"}.join '|'})+"
8
+
9
+ def process(base_file, deps)
10
+ @script, @directives = strip_directives read_base_file(base_file)
11
+ return @script unless @directives
12
+ @dependencies = deps
13
+ @output = ''
14
+ @base_file = base_file
15
+ @marks = {append_self: ->{ @output += @script }}
16
+ @directives.each{|args| directive args, :pre }
17
+ @marks[:append_self].call if @marks[:append_self]
18
+ @directives.each{|args| directive args, :post }
19
+ @output
20
+ end
21
+
22
+ def pre_prepend(args)
23
+ file = find_nested_file(args.first)
24
+ cached_file, deps = get_nested_piece file
25
+ @dependencies.concat deps
26
+ @script = "#{File.read cached_file}#{@script}"
27
+ end
28
+
29
+ def pre_append(args)
30
+ file = find_nested_file(args.first)
31
+ cached_file, deps = get_nested_piece file
32
+ @dependencies.concat deps
33
+ @script = "#{@script}#{File.read cached_file}"
34
+ end
35
+
36
+ def pre_depend_on(args)
37
+ file = find_nested_file(args[1])
38
+ @dependencies << ::Gluey::Dependencies::SingleFile.new(file).actualize
39
+ end
40
+
41
+ private
42
+
43
+ def strip_directives(data)
44
+ script = data
45
+ directives = data[DIRECTIVES_REGEXP]
46
+ if directives
47
+ script = $'
48
+ directives = directives.split("\n").reject{|dir| dir.empty?}.map do |dir|
49
+ dir.strip[/(?:#{PREFIXES.join '|'}=)\s*(.+)/, 1].split (' ')
50
+ end
51
+ end
52
+ return script, directives
53
+ end
54
+
55
+ def directive(dir_array, run)
56
+ method = "#{run}_#{dir_array.first}"
57
+ send method, dir_array[1..-1] if respond_to? method
58
+ end
59
+
60
+ def find_nested_file(rel_path)
61
+ file = File.expand_path("../#{rel_path}", @base_file)
62
+ File.exists?(file) || raise("cannot find '#{rel_path}' from script=#{@base_file}")
63
+ file
64
+ end
65
+
66
+ def get_nested_piece(file)
67
+ path = file[/(?:^#{@context.root_path}\/)?(.+)$/, 1]
68
+ key = "script_piece:#{@material.name}:#{path}"
69
+ cache_file, dependencies = @context.cache[key]
70
+ return cache_file, dependencies if cache_file && File.exists?(cache_file) && !dependencies.any?{|dep| dep.changed?}
71
+
72
+ glue = self.class.new @context, @material
73
+ cache_dir = "#{@context.tmp_path}/.script"
74
+ Dir.mkdir cache_dir unless Dir.exists? cache_dir
75
+ cache_file = "#{cache_dir}/#{path}.#{@material.name}"
76
+ dependencies = [::Gluey::Dependencies::SingleFile.new(file).actualize]
77
+ FileUtils.mkdir_p cache_file[0..(cache_file.rindex('/')-1)]
78
+ File.write cache_file, glue.process(file, dependencies)
79
+ @context.cache[key] = [cache_file, dependencies]
80
+ return cache_file, dependencies
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1,74 @@
1
+ require_relative 'exceptions/file_not_found'
2
+
3
+ class Gluey::Material
4
+
5
+ attr_reader :name, :glue
6
+ attr_accessor :asset, :file_extension, :public_dir
7
+
8
+ def initialize(name, glue, context)
9
+ @name = name.to_sym
10
+ @glue = glue
11
+ @context = context
12
+ @asset = name.to_s
13
+ @paths = []
14
+ @items = []
15
+ yield self if block_given?
16
+ @file_extension ||= @asset.dup
17
+ end
18
+
19
+ def add_path(path)
20
+ @paths << path
21
+ end
22
+
23
+ def add_item(declaration)
24
+ @items << declaration
25
+ end
26
+
27
+ def is_listed?(path, file=nil)
28
+ @items.any? do |items_declaration|
29
+ case items_declaration
30
+ when String
31
+ path == items_declaration
32
+ when Regexp
33
+ path =~ items_declaration
34
+ when Proc
35
+ items_declaration[path, file]
36
+ end
37
+ end
38
+ end
39
+
40
+ def to_s
41
+ "Material #{@name}"
42
+ end
43
+
44
+ def find_base_file(path)
45
+ paths.each do |base_path|
46
+ p = "#{base_path}/#{path}.#{@file_extension}"; return p if File.exists? p
47
+ p = "#{p}.erb"; return p if File.exists? p
48
+ p = "#{base_path}/#{path}/index.#{@file_extension}"; return p if File.exists? p
49
+ p = "#{p}.erb"; return p if File.exists? p
50
+ end
51
+ raise(::Gluey::FileNotFound.new "#{to_s} cannot find base file for #{path}")
52
+ end
53
+
54
+ def list_all_items
55
+ list = []
56
+ paths.map do |base_path|
57
+ glob_path = "#{base_path}/**/*.#{@file_extension}"
58
+ files = Dir[glob_path] + Dir["#{glob_path}.erb"]
59
+ files.select do |file|
60
+ path = file[/^#{base_path}\/(.+)\.#{@file_extension}(?:\.erb)?$/, 1]
61
+ path.gsub! /\/index$/, ''
62
+ list << path if is_listed? path, file
63
+ end
64
+ end
65
+ list.uniq
66
+ end
67
+
68
+ private
69
+
70
+ def paths
71
+ @paths.map{|p| "#{@context.root_path}/#{p}"}
72
+ end
73
+
74
+ end
@@ -0,0 +1,86 @@
1
+ require_relative 'tools'
2
+
3
+ module Gluey::Tools
4
+
5
+ def self.build_into_public_dir(workshop, warehouse, public_dir='public/assets', **builders)
6
+ public_dirs = workshop.materials.values.inject({}) do |h, m|
7
+ h[m.name] = "#{workshop.root_path}/#{m.public_dir || public_dir}"
8
+ h
9
+ end
10
+
11
+ built = []
12
+ move_it = -> (cache_file, file) { FileUtils.mv cache_file, file }
13
+ self.each_asset_file workshop, warehouse do |cache_file, type, path|
14
+ file = "#{public_dirs[type]}/#{path}"
15
+ next if File.exists? file
16
+ FileUtils.mkdir_p file[0..(file.rindex('/')-1)]
17
+ (builders[type] || move_it)[cache_file, file]
18
+ built << file
19
+ puts "created #{file}"
20
+ end
21
+ return built
22
+ end
23
+
24
+ def self.clear_public_dir(workshop, warehouse, versions=2, public_dir='public/assets')
25
+ public_dirs = workshop.materials.values.inject({}) do |h, m|
26
+ h[m.name] = "#{workshop.root_path}/#{m.public_dir || public_dir}"
27
+ h
28
+ end
29
+
30
+ # process existing files into assets
31
+ eas_regexp = /^#{workshop.root_path}\/(.+)$/
32
+ assets = public_dirs.values.uniq.map{|dir| Dir["#{dir}/**/*.*.*"]}.flatten.
33
+ map{|f| Asset.try_create f[eas_regexp, 1]}.compact
34
+ assets = assets.inject({}){|h, asset| (h[asset.path] ||= []) << asset; h }
35
+
36
+ # items not on list
37
+ on_list = []
38
+ warehouse.assets.each do |type, mater_assets|
39
+ mater_assets.each do |_, real_path|
40
+ file = "#{public_dirs[type]}/#{real_path}"
41
+ asset = Asset.try_create file[eas_regexp, 1]
42
+ on_list << asset
43
+ end
44
+ end
45
+ on_list.map! &:path
46
+ assets.delete_if do |path, asseets_arr|
47
+ unless on_list.include? path
48
+ asseets_arr.each do |some_asset|
49
+ file = "#{workshop.root_path}/#{some_asset.orig_path}"
50
+ File.delete file
51
+ puts "deleted unknown #{file}"
52
+ end
53
+ true
54
+ end
55
+ false
56
+ end
57
+
58
+ # older versions
59
+ assets.values.select{|arr| arr.length > versions}.
60
+ map{|arr| arr.sort.slice 0..(-versions-1) }.compact.flatten.each do |old_asset|
61
+ file = "#{workshop.root_path}/#{old_asset.orig_path}"
62
+ File.delete file
63
+ puts "deleted old #{file}"
64
+ end
65
+ end
66
+
67
+ class Asset < Struct.new(:path, :time_stamp)
68
+
69
+ def self.try_create(file)
70
+ file.match /^([^\.]+)\.(\d+)\.(\w+)$/ do |m|
71
+ new "#{m[1]}.#{m[3]}", m[2]
72
+ end
73
+ end
74
+
75
+ def <=>(other)
76
+ time_stamp <=> other.time_stamp
77
+ end
78
+
79
+ def orig_path
80
+ ret = path.dup
81
+ ret.insert ret.rindex('.'), ".#{time_stamp}"
82
+ end
83
+
84
+ end
85
+
86
+ end
@@ -0,0 +1,19 @@
1
+ require 'gluey/warehouse'
2
+
3
+ module Gluey::Tools
4
+
5
+ def self.each_asset_file(workshop, warehouse)
6
+ warehouse.assets.each do |type, assets|
7
+ assets.each do |path, real_path|
8
+ cache_file = workshop.fetch_file type, path
9
+ yield cache_file, type, real_path
10
+ end
11
+ end
12
+ end
13
+
14
+ def self.create_uglifier_builder(**opts)
15
+ require 'uglifier'
16
+ ->(a, b){File.write b, ::Uglifier.new(opts.merge! copyright: :none).compile(File.read a)}
17
+ end
18
+
19
+ end
@@ -0,0 +1,3 @@
1
+ module Gluey
2
+ VERSION = '0.2.2'
3
+ end
@@ -0,0 +1,50 @@
1
+ require_relative '../gluey'
2
+ require_relative 'exceptions/item_not_listed'
3
+ require 'json'
4
+
5
+ class Gluey::Warehouse
6
+
7
+ attr_reader :assets
8
+
9
+ def initialize(root, listing_file='assets/gluey_listing.json')
10
+ @listing_file = "#{root}/#{listing_file}"
11
+ read_listing
12
+ end
13
+
14
+ def real_path(asset_type, path)
15
+ listing = @assets[asset_type]
16
+ unless listing
17
+ raise ::Gluey::ItemNotListed.new("Asset type #{asset_type} is not defined! (listing file problem?)")
18
+ end
19
+
20
+ real_path = listing[path]
21
+ unless real_path
22
+ raise ::Gluey::ItemNotListed.new("Unknown asset: #{path}, type=#{asset_type}! (listing file problem?)")
23
+ end
24
+
25
+ real_path
26
+ end
27
+
28
+ def read_listing
29
+ assets = if File.exists? @listing_file
30
+ JSON.parse File.read(@listing_file) rescue {}
31
+ else
32
+ {}
33
+ end
34
+ raise "corrupted listing file at #{@listing_file}" unless assets.is_a? Hash
35
+ @assets = assets.keys.inject({}){|h, asset_type| h[asset_type.to_sym] = assets[asset_type]; h }
36
+ end
37
+
38
+ def write_listing(workshop)
39
+ @assets = workshop.materials.values.inject({}) do |listing, material|
40
+ list = material.list_all_items.inject({}) do |h, path|
41
+ h[path] = workshop.real_path material.name, path
42
+ h
43
+ end
44
+ listing[material.name.to_sym] = list
45
+ listing
46
+ end
47
+ File.write @listing_file, JSON.pretty_generate(@assets)
48
+ end
49
+
50
+ end
@@ -0,0 +1,64 @@
1
+ require_relative '../gluey'
2
+
3
+ require_relative 'exceptions/item_not_listed'
4
+
5
+ require_relative 'material'
6
+ require_relative 'glues/base'
7
+
8
+ class Gluey::Workshop
9
+
10
+ attr_reader :root_path, :tmp_path, :materials, :cache
11
+
12
+ def initialize(root, tmp_dir='tmp/gluey')
13
+ @root_path = root
14
+ @tmp_path = "#{root}/#{tmp_dir}"
15
+ Dir.mkdir @tmp_path unless Dir.exists? @tmp_path
16
+ @materials = {}
17
+ @cache = {}
18
+ end
19
+
20
+ def register_material(name, glue=::Gluey::Glues::Base, &block)
21
+ name = name.to_sym
22
+ material = ::Gluey::Material.new name, glue, self, &block
23
+ @materials[name] = material
24
+ end
25
+
26
+ def fetch_file(material, path)
27
+ # check cache
28
+ cache_key = "lump:#{material}:#{path}"
29
+ file, dependencies = @cache[cache_key]
30
+ if file && File.exists?(file) && !dependencies.any?{|d| d.changed?}
31
+ return file
32
+ end
33
+
34
+ # prepare for processing
35
+ material = @materials[material.to_sym]
36
+ base_file = material.find_base_file path
37
+ file = "#{@tmp_path}/#{path}.#{material.asset}"
38
+ dependencies = [::Gluey::Dependencies::SingleFile.new(base_file).actualize]
39
+ # process
40
+ glue = material.glue.new self, material
41
+ FileUtils.mkdir_p file[0..(file.rindex('/')-1)]
42
+ File.write file, glue.process(base_file, dependencies)
43
+
44
+ # save and return
45
+ @cache[cache_key] = [file, dependencies]
46
+ file
47
+ end
48
+
49
+ def real_path(material, path)
50
+ material = @materials[material.to_sym]
51
+ file = material.find_base_file path
52
+ unless material.is_listed? path, file
53
+ raise ::Gluey::ItemNotListed.new("#{material.to_s} doesn't have enlisted item #{path} (file=#{file}).")
54
+ end
55
+ "#{path}.#{File.mtime(file).to_i}.#{material.asset}"
56
+ end
57
+
58
+ def try_real_path(path)
59
+ path.match /^(.+)\.\d+\.(\w+)$/ do |m|
60
+ yield m[1], m[2]
61
+ end
62
+ end
63
+
64
+ end
data/lib/gluey.rb ADDED
@@ -0,0 +1,2 @@
1
+
2
+ require_relative 'gluey/version'
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gluey
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.2
5
+ platform: ruby
6
+ authors:
7
+ - doooby
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-08-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description: Concatenating and processing asset files with possibly complicated dependencies.
42
+ email:
43
+ - zelazk.o@email.cz
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - Gemfile
50
+ - LICENSE.txt
51
+ - README.md
52
+ - Rakefile
53
+ - gluey.gemspec
54
+ - lib/gluey.rb
55
+ - lib/gluey/dependencies/directory.rb
56
+ - lib/gluey/dependencies/handlebars_bundle.rb
57
+ - lib/gluey/dependencies/single_file.rb
58
+ - lib/gluey/dependencies/texts_bundle.rb
59
+ - lib/gluey/exceptions/file_not_found.rb
60
+ - lib/gluey/exceptions/item_not_listed.rb
61
+ - lib/gluey/glues/base.rb
62
+ - lib/gluey/glues/js_script.rb
63
+ - lib/gluey/glues/js_script/handlebars_addons.rb
64
+ - lib/gluey/glues/sass.rb
65
+ - lib/gluey/glues/script.rb
66
+ - lib/gluey/material.rb
67
+ - lib/gluey/tools/local_build.rb
68
+ - lib/gluey/tools/tools.rb
69
+ - lib/gluey/version.rb
70
+ - lib/gluey/warehouse.rb
71
+ - lib/gluey/workshop.rb
72
+ homepage:
73
+ licenses:
74
+ - MIT
75
+ metadata: {}
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubyforge_project:
92
+ rubygems_version: 2.2.2
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: Rails' asset pipelane replacement
96
+ test_files: []