dassets 0.6.2 → 0.7.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.
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