dassets 0.6.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -25,24 +25,6 @@ Dassets.configure do |c|
25
25
  end
26
26
  ```
27
27
 
28
- ### Digest
29
-
30
- You can use the CLI to digest your source files on demand:
31
-
32
- ```
33
- $ dassets digest # digest all source files, OR
34
- $ dassets digest /path/to/source/file # digest some specific files
35
- ```
36
-
37
- Or you can programmatically digest files as needed:
38
-
39
- ```ruby
40
- Dassets.digest_source_files # digest all source files, OR
41
- Dassets.digest_source_files ['/path/to/source/file'] # digest just some specific files
42
- ```
43
-
44
- Digesting involves combining, compiling, fingerprinting, and outputting each source file. Once a source has been digested, it is available for linking, serving, and/or caching.
45
-
46
28
  ### Link To
47
29
 
48
30
  ```rb
@@ -53,7 +35,7 @@ Dassets['img/logos/main.jpg'].href # => "/img/logos/main-a1b2c3.jpg"
53
35
 
54
36
  ### Serve
55
37
 
56
- In development, use the Dassets middleware to serve your digested asset files:
38
+ Use the Dassets middleware to serve your digested asset files:
57
39
 
58
40
  ```ruby
59
41
  # `app` is a rack application
@@ -61,15 +43,6 @@ require 'dassets/server'
61
43
  app.use Dassets::Server
62
44
  ```
63
45
 
64
- In production, use the CLI to cache your digested asset files to the public dir:
65
-
66
- ```
67
- # call the CLI in your deploy scripts or whatever
68
- $ dassets cache /path/to/public/dir
69
- ```
70
-
71
- TODO: programmatically cache asset files
72
-
73
46
  ## Compiling
74
47
 
75
48
  Dassets compiles your asset source as part of its digest pipeline using "engines". Engines transform source extensions and content.
@@ -1,18 +1,19 @@
1
1
  require 'fileutils'
2
2
  require 'dassets'
3
3
  require 'dassets/asset_file'
4
+ require 'dassets/source_proxy'
4
5
 
5
6
  module Dassets
6
7
 
7
8
  class SourceFile
8
9
 
9
- def self.find_by_digest_path(path)
10
+ def self.find_by_digest_path(path, cache = nil)
10
11
  # look in the configured source list
11
12
  source_files = Dassets.source_list.map{ |p| self.new(p) }
12
13
 
13
14
  # get the last matching one (in case two source files have the same digest
14
15
  # path the last one *should* be correct since it was last to be configured)
15
- source_files.select{ |s| s.digest_path == path }.last || NullSourceFile.new(path)
16
+ source_files.select{ |s| s.digest_path == path }.last || NullSourceFile.new(path, cache)
16
17
  end
17
18
 
18
19
  attr_reader :file_path
@@ -80,16 +81,34 @@ module Dassets
80
81
 
81
82
  end
82
83
 
84
+ # A null source file is used to represent source that either doesn't exist
85
+ # or source that is a proxy (ie a combination)
86
+
83
87
  class NullSourceFile < SourceFile
84
- attr_reader :file_path, :digest_path, :compiled, :fingerprint
85
- def initialize(digest_path)
86
- @file_path = ''
87
- @ext_list = []
88
+
89
+ def initialize(digest_path, cache = nil)
90
+ @file_path, @ext_list = '', []
88
91
  @digest_path = digest_path
92
+ @source_compiled, @source_exists, @source_mtime = nil, false, nil
93
+
94
+ # if the digest path is a combination, build its proxy and use relevent
95
+ # properties as the source file properties
96
+ if Dassets.config.combination?(@digest_path)
97
+ source_proxy = SourceProxy.new(@digest_path, cache)
98
+ @source_compiled = source_proxy.content
99
+ @source_exists = source_proxy.exists?
100
+ @source_mtime = source_proxy.mtime
101
+ end
89
102
  end
103
+
104
+ def compiled; @source_compiled; end
105
+ def exists?; @source_exists; end
106
+ def mtime; @source_mtime; end
107
+
90
108
  def ==(other_source_file)
91
109
  self.file_path == other_source_file.file_path
92
110
  end
111
+
93
112
  end
94
113
 
95
114
  end
@@ -6,10 +6,10 @@ class Dassets::SourceProxy
6
6
 
7
7
  attr_reader :digest_path, :source_files, :cache
8
8
 
9
- def initialize(digest_path, cache=nil)
9
+ def initialize(digest_path, cache = nil)
10
10
  @digest_path = digest_path
11
- @source_files = get_source_files(@digest_path)
12
11
  @cache = cache || NoCache.new
12
+ @source_files = get_source_files(@digest_path, @cache)
13
13
  end
14
14
 
15
15
  def key
@@ -42,9 +42,9 @@ class Dassets::SourceProxy
42
42
  @source_fingerprint ||= Digest::MD5.new.hexdigest(source_content)
43
43
  end
44
44
 
45
- def get_source_files(digest_path)
45
+ def get_source_files(digest_path, cache)
46
46
  Dassets.config.combinations[digest_path.to_s].map do |source_digest_path|
47
- Dassets::SourceFile.find_by_digest_path(source_digest_path)
47
+ Dassets::SourceFile.find_by_digest_path(source_digest_path, cache)
48
48
  end
49
49
  end
50
50
 
@@ -1,3 +1,3 @@
1
1
  module Dassets
2
- VERSION = "0.6.2"
2
+ VERSION = "0.7.0"
3
3
  end
data/lib/dassets.rb CHANGED
@@ -32,13 +32,6 @@ module Dassets
32
32
  SourceList.new(self.config.sources)
33
33
  end
34
34
 
35
- # Cmds
36
-
37
- def self.digest_source_files(paths=nil)
38
- require 'dassets/digest_cmd'
39
- DigestCmd.new(paths).run
40
- end
41
-
42
35
  class Config
43
36
  include NsOptions::Proxy
44
37
 
@@ -51,7 +44,7 @@ module Dassets
51
44
  def initialize
52
45
  super
53
46
  @sources = []
54
- @combinations = Hash.new{ |h,k| [k] } # digest pass-thru if none defined
47
+ @combinations = Hash.new{ |h, k| [k] } # digest pass-thru if none defined
55
48
  @cache = DefaultCache.new
56
49
  end
57
50
 
@@ -62,6 +55,12 @@ module Dassets
62
55
  def combination(key_digest_path, value_digest_paths)
63
56
  @combinations[key_digest_path.to_s] = [*value_digest_paths]
64
57
  end
58
+
59
+ def combination?(key_digest_path)
60
+ # a digest path is only considered a combination is it is not the default
61
+ # pass-thru above
62
+ @combinations[key_digest_path.to_s] != [key_digest_path]
63
+ end
65
64
  end
66
65
 
67
66
  module SourceList
@@ -16,7 +16,7 @@ class Dassets::Config
16
16
  should have_options :file_store
17
17
 
18
18
  should have_reader :combinations
19
- should have_imeth :source, :combination
19
+ should have_imeth :source, :combination, :combination?
20
20
 
21
21
  should "register new sources with the `source` method" do
22
22
  path = '/path/to/app/assets'
@@ -45,6 +45,13 @@ class Dassets::Config
45
45
  assert_equal ['some/other.path'], subject.combinations['test/digest.path']
46
46
  end
47
47
 
48
+ should "know which digest paths are actual combinations and which are just pass-thrus" do
49
+ subject.combination 'some/combination.path', ['some.path', 'another.path']
50
+
51
+ assert subject.combination? 'some/combination.path'
52
+ assert_not subject.combination? 'some/non-combo.path'
53
+ end
54
+
48
55
  end
49
56
 
50
57
  end
@@ -9,7 +9,7 @@ module Dassets
9
9
  subject{ Dassets }
10
10
 
11
11
  should have_imeths :config, :configure, :init, :[]
12
- should have_imeths :source_list, :digest_source_files
12
+ should have_imeths :source_list
13
13
 
14
14
  should "return a `Config` instance with the `config` method" do
15
15
  assert_kind_of Config, subject.config
@@ -1,10 +1,11 @@
1
1
  require 'assert'
2
- require 'dassets/asset_file'
3
2
  require 'dassets/source_file'
4
3
 
4
+ require 'dassets/asset_file'
5
+
5
6
  class Dassets::SourceFile
6
7
 
7
- class BaseTests < Assert::Context
8
+ class UnitTests < Assert::Context
8
9
  desc "Dassets::SourceFile"
9
10
  setup do
10
11
  @file_path = TEST_SUPPORT_PATH.join('app/assets/file1.txt').to_s
@@ -50,17 +51,38 @@ class Dassets::SourceFile
50
51
  assert_not_same subject, found
51
52
  end
52
53
 
54
+ end
55
+
56
+ class NullSourceTests < UnitTests
57
+
53
58
  should "find a null src file if finding by an unknown digest path" do
54
59
  null_src = Dassets::NullSourceFile.new('not/found/digest/path')
55
60
  found = Dassets::SourceFile.find_by_digest_path('not/found/digest/path')
56
61
 
57
- assert_equal null_src, found
62
+ assert_equal null_src, found
58
63
  assert_not_same null_src, found
64
+
65
+ assert_equal '', null_src.file_path
66
+ assert_equal false, null_src.exists?
67
+ assert_nil null_src.compiled
68
+ assert_nil null_src.mtime
69
+ end
70
+
71
+ should "'proxy' the digest path if the path is a combination" do
72
+ Dassets.config.combination 'file3.txt', ['file1.txt', 'file2.txt']
73
+ src_proxy = Dassets::SourceProxy.new('file3.txt')
74
+ null_combo_src = Dassets::NullSourceFile.new('file3.txt')
75
+
76
+ assert_equal src_proxy.exists?, null_combo_src.exists?
77
+ assert_equal src_proxy.content, null_combo_src.compiled
78
+ assert_equal src_proxy.mtime, null_combo_src.mtime
79
+
80
+ Dassets.config.combinations.delete('file3.txt')
59
81
  end
60
82
 
61
83
  end
62
84
 
63
- class EngineTests < BaseTests
85
+ class EngineTests < UnitTests
64
86
  desc "compiled against engines"
65
87
  setup do
66
88
  @file_path = TEST_SUPPORT_PATH.join('app/assets/nested/a-thing.txt.useless.dumb')
metadata CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 6
9
- - 2
10
- version: 0.6.2
8
+ - 7
9
+ - 0
10
+ version: 0.7.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Kelly Redding
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2013-06-12 00:00:00 Z
19
+ date: 2013-08-07 00:00:00 Z
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
22
  name: assert
@@ -97,8 +97,8 @@ description: Digest and serve HTML asset files
97
97
  email:
98
98
  - kelly@kellyredding.com
99
99
  - collin.redding@me.com
100
- executables:
101
- - dassets
100
+ executables: []
101
+
102
102
  extensions: []
103
103
 
104
104
  extra_rdoc_files: []
@@ -109,16 +109,12 @@ files:
109
109
  - LICENSE.txt
110
110
  - README.md
111
111
  - Rakefile
112
- - bin/dassets
113
112
  - dassets.gemspec
114
113
  - lib/dassets.rb
115
114
  - lib/dassets/asset_file.rb
116
- - lib/dassets/cli.rb
117
115
  - lib/dassets/default_cache.rb
118
- - lib/dassets/digest_cmd.rb
119
116
  - lib/dassets/engine.rb
120
117
  - lib/dassets/file_store.rb
121
- - lib/dassets/runner.rb
122
118
  - lib/dassets/server.rb
123
119
  - lib/dassets/server/request.rb
124
120
  - lib/dassets/server/response.rb
@@ -145,16 +141,13 @@ files:
145
141
  - test/support/source_files/nested/_nested_ignored.txt
146
142
  - test/support/source_files/nested/test2.txt
147
143
  - test/support/source_files/test1.txt
148
- - test/system/digest_cmd_run_tests.rb
149
144
  - test/system/rack_tests.rb
150
145
  - test/unit/asset_file_tests.rb
151
146
  - test/unit/config_tests.rb
152
147
  - test/unit/dassets_tests.rb
153
148
  - test/unit/default_cache_tests.rb
154
- - test/unit/digest_cmd_tests.rb
155
149
  - test/unit/engine_tests.rb
156
150
  - test/unit/file_store_tests.rb
157
- - test/unit/runner_tests.rb
158
151
  - test/unit/server/request_tests.rb
159
152
  - test/unit/server/response_tests.rb
160
153
  - test/unit/server_tests.rb
@@ -214,16 +207,13 @@ test_files:
214
207
  - test/support/source_files/nested/_nested_ignored.txt
215
208
  - test/support/source_files/nested/test2.txt
216
209
  - test/support/source_files/test1.txt
217
- - test/system/digest_cmd_run_tests.rb
218
210
  - test/system/rack_tests.rb
219
211
  - test/unit/asset_file_tests.rb
220
212
  - test/unit/config_tests.rb
221
213
  - test/unit/dassets_tests.rb
222
214
  - test/unit/default_cache_tests.rb
223
- - test/unit/digest_cmd_tests.rb
224
215
  - test/unit/engine_tests.rb
225
216
  - test/unit/file_store_tests.rb
226
- - test/unit/runner_tests.rb
227
217
  - test/unit/server/request_tests.rb
228
218
  - test/unit/server/response_tests.rb
229
219
  - test/unit/server_tests.rb
data/bin/dassets DELETED
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env ruby
2
- #
3
- # Copyright (c) 2013-Present Kelly Redding and Collin Redding
4
- #
5
-
6
- require 'dassets/cli'
7
- Dassets::CLI.run *ARGV
data/lib/dassets/cli.rb DELETED
@@ -1,109 +0,0 @@
1
- require 'dassets/version'
2
- require 'dassets/runner'
3
-
4
- module Dassets
5
-
6
- class CLI
7
-
8
- def self.run(*args)
9
- self.new.run(*args)
10
- end
11
-
12
- def initialize
13
- @cli = CLIRB.new
14
- end
15
-
16
- def run(*args)
17
- begin
18
- @cli.parse!(args)
19
- Dassets::Runner.new(@cli.args, @cli.opts).run
20
- rescue CLIRB::HelpExit
21
- puts help
22
- rescue CLIRB::VersionExit
23
- puts Dassets::VERSION
24
- rescue Dassets::Runner::UnknownCmdError => err
25
- $stderr.puts "#{err.message}\n\n"
26
- $stderr.puts help
27
- exit(1)
28
- rescue Dassets::Runner::CmdError => err
29
- $stderr.puts "#{err.message}"
30
- exit(1)
31
- rescue Dassets::Runner::CmdFail => err
32
- exit(1)
33
- rescue CLIRB::Error => exception
34
- $stderr.puts "#{exception.message}\n\n"
35
- $stderr.puts help
36
- exit(1)
37
- rescue Exception => exception
38
- $stderr.puts "#{exception.class}: #{exception.message}"
39
- $stderr.puts exception.backtrace.join("\n")
40
- exit(1)
41
- end
42
- exit(0)
43
- end
44
-
45
- def help
46
- "Usage: dassets [options] COMMAND\n"\
47
- "\n"\
48
- "Options:"\
49
- "#{@cli}"
50
- end
51
-
52
- end
53
-
54
- class CLIRB # Version 1.0.0, https://github.com/redding/cli.rb
55
- Error = Class.new(RuntimeError);
56
- HelpExit = Class.new(RuntimeError); VersionExit = Class.new(RuntimeError)
57
- attr_reader :argv, :args, :opts, :data
58
-
59
- def initialize(&block)
60
- @options = []; instance_eval(&block) if block
61
- require 'optparse'
62
- @data, @args, @opts = [], [], {}; @parser = OptionParser.new do |p|
63
- p.banner = ''; @options.each do |o|
64
- @opts[o.name] = o.value; p.on(*o.parser_args){ |v| @opts[o.name] = v }
65
- end
66
- p.on_tail('--version', ''){ |v| raise VersionExit, v.to_s }
67
- p.on_tail('--help', ''){ |v| raise HelpExit, v.to_s }
68
- end
69
- end
70
-
71
- def option(*args); @options << Option.new(*args); end
72
- def parse!(argv)
73
- @args = (argv || []).dup.tap do |args_list|
74
- begin; @parser.parse!(args_list)
75
- rescue OptionParser::ParseError => err; raise Error, err.message; end
76
- end; @data = @args + [@opts]
77
- end
78
- def to_s; @parser.to_s; end
79
- def inspect
80
- "#<#{self.class}:#{'0x0%x' % (object_id << 1)} @data=#{@data.inspect}>"
81
- end
82
-
83
- class Option
84
- attr_reader :name, :opt_name, :desc, :abbrev, :value, :klass, :parser_args
85
-
86
- def initialize(name, *args)
87
- settings, @desc = args.last.kind_of?(::Hash) ? args.pop : {}, args.pop || ''
88
- @name, @opt_name, @abbrev = parse_name_values(name, settings[:abbrev])
89
- @value, @klass = gvalinfo(settings[:value])
90
- @parser_args = if [TrueClass, FalseClass, NilClass].include?(@klass)
91
- ["-#{@abbrev}", "--[no-]#{@opt_name}", @desc]
92
- else
93
- ["-#{@abbrev}", "--#{@opt_name} #{@opt_name.upcase}", @klass, @desc]
94
- end
95
- end
96
-
97
- private
98
-
99
- def parse_name_values(name, custom_abbrev)
100
- [ (processed_name = name.to_s.strip.downcase), processed_name.gsub('_', '-'),
101
- custom_abbrev || processed_name.gsub(/[^a-z]/, '').chars.first || 'a'
102
- ]
103
- end
104
- def gvalinfo(v); v.kind_of?(Class) ? [nil,gklass(v)] : [v,gklass(v.class)]; end
105
- def gklass(k); k == Fixnum ? Integer : k; end
106
- end
107
- end
108
-
109
- end
@@ -1,41 +0,0 @@
1
- require 'fileutils'
2
- require 'dassets'
3
- require 'dassets/source_file'
4
-
5
- module Dassets; end
6
- class Dassets::DigestCmd
7
-
8
- # TODO: need digest cmd to be aware of and digest combinations as well.
9
- # going to wait on this for now b/c there are changes coming to how sources
10
- # are obtained and the future of the digest cmd and I want to see how thost
11
- # end up first.
12
-
13
- attr_reader :paths
14
-
15
- def initialize(abs_paths)
16
- @paths = abs_paths || []
17
- end
18
-
19
- def run(io=nil)
20
- files = @paths
21
- if @paths.empty?
22
- # always get the latest source list
23
- files = Dassets.source_list
24
- end
25
-
26
- log io, "digesting #{files.count} source file(s) ..."
27
- digest_the_files(files)
28
- end
29
-
30
- private
31
-
32
- def digest_the_files(files)
33
- files.each{ |f| Dassets::SourceFile.new(f).asset_file.digest! }
34
- end
35
-
36
- def log(io, msg)
37
- io.puts msg if io
38
- end
39
-
40
- end
41
-
@@ -1,39 +0,0 @@
1
- require 'dassets'
2
-
3
- module Dassets; end
4
- class Dassets::Runner
5
- UnknownCmdError = Class.new(ArgumentError)
6
- CmdError = Class.new(RuntimeError)
7
- CmdFail = Class.new(RuntimeError)
8
-
9
- attr_reader :cmd_name, :cmd_args, :opts
10
-
11
- def initialize(args, opts)
12
- @opts = opts
13
- @cmd_name = args.shift || ""
14
- @cmd_args = args
15
- @pwd = ENV['PWD']
16
- end
17
-
18
- def run
19
- Dassets.init
20
-
21
- case @cmd_name
22
- when 'digest'
23
- require 'dassets/digest_cmd'
24
- abs_paths = @cmd_args.map{ |path| File.expand_path(path, @pwd) }
25
- Dassets::DigestCmd.new(abs_paths).run($stdout)
26
- when 'null'
27
- NullCommand.new.run
28
- else
29
- raise UnknownCmdError, "unknown command `#{@cmd_name}`"
30
- end
31
- end
32
-
33
- class NullCommand
34
- def run
35
- # if this was a real command it would do something here
36
- end
37
- end
38
-
39
- end
@@ -1,68 +0,0 @@
1
- require 'assert'
2
- require 'fileutils'
3
- require 'dassets'
4
-
5
- module Dassets
6
-
7
- class DigestCmdRunTests < Assert::Context
8
- desc "the DigestCmd"
9
- setup do
10
- Dassets.config.file_store = TEST_SUPPORT_PATH.join('public').to_s
11
- clear_store_path(Dassets.config.file_store.root)
12
- Dassets.digest_source_files
13
-
14
- @addfile = 'addfile.txt'
15
- @addfile_src = source_path(@addfile)
16
-
17
- @rmfile = 'file1.txt'
18
- @rmfile_src = source_path(@rmfile)
19
- @rmfile_contents = File.read(@rmfile_src)
20
-
21
- FileUtils.touch @addfile_src
22
- @addfile_out = store_path(@addfile)
23
-
24
- @rmfile_out = store_path(@rmfile)
25
- FileUtils.rm @rmfile_src
26
- end
27
- teardown do
28
- File.open(@rmfile_src, "w"){ |f| f.write @rmfile_contents }
29
- FileUtils.rm @addfile_src
30
-
31
- Dassets.digest_source_files
32
- clear_store_path(Dassets.config.file_store.root)
33
- Dassets.digest_source_files
34
- Dassets.config.file_store = NullFileStore.new
35
- end
36
-
37
- should "update the digests on all source files when run with no given paths" do
38
- clear_store_path(Dassets.config.file_store.root)
39
- Dassets.digest_source_files
40
-
41
- assert_file_exists @addfile_out
42
- assert_not_file_exists @rmfile_out
43
- end
44
-
45
- should "update the digests on a single source file when given its path" do
46
- clear_store_path(Dassets.config.file_store.root)
47
- Dassets.digest_source_files([@addfile_src])
48
-
49
- assert_file_exists @addfile_out
50
- end
51
-
52
- private
53
-
54
- def source_path(file)
55
- File.join(Dassets.config.sources.first.path, file)
56
- end
57
-
58
- def store_path(file)
59
- Dassets.config.file_store.store_path(Dassets::AssetFile.new(file).url)
60
- end
61
-
62
- def clear_store_path(path)
63
- Dir.glob(File.join(path, '*')).each{ |p| FileUtils.rm_r(p) } if path
64
- end
65
-
66
- end
67
-
68
- end
@@ -1,23 +0,0 @@
1
- require 'assert'
2
- require 'dassets'
3
- require 'dassets/digest_cmd'
4
-
5
- class Dassets::DigestCmd
6
-
7
- class BaseTests < Assert::Context
8
- desc "Dassets::DigestCmd"
9
- setup do
10
- @cmd = Dassets::DigestCmd.new(['a/path'])
11
- end
12
- subject{ @cmd }
13
-
14
- should have_readers :paths
15
- should have_instance_method :run
16
-
17
- should "know it's paths" do
18
- assert_equal ['a/path'], subject.paths
19
- end
20
-
21
- end
22
-
23
- end
@@ -1,29 +0,0 @@
1
- require 'assert'
2
- require 'pathname'
3
- require 'dassets/runner'
4
-
5
- class Dassets::Runner
6
-
7
- class BaseTests < Assert::Context
8
- desc "Dassets::Runner"
9
- setup do
10
- @runner = Dassets::Runner.new(['null', 1, 2], 'some' => 'opts')
11
- end
12
- subject{ @runner }
13
-
14
- should have_readers :cmd_name, :cmd_args, :opts
15
-
16
- should "know its cmd, cmd_args, and opts" do
17
- assert_equal 'null', subject.cmd_name
18
- assert_equal [1,2], subject.cmd_args
19
- assert_equal 'opts', subject.opts['some']
20
- end
21
-
22
- should "complain about unknown cmds" do
23
- runner = Dassets::Runner.new(['unknown'], {})
24
- assert_raises(UnknownCmdError) { runner.run }
25
- end
26
-
27
- end
28
-
29
- end