dassets 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -14,22 +14,13 @@ require 'dassets'
14
14
 
15
15
  Dassets.configure do |c|
16
16
 
17
- # tell Dassets what the root path of your app is
18
- c.root_path '/path/to/app/root'
19
-
20
- # tell Dassets where to look for source files and (optionally) how to filter those files
21
- c.source_path 'lib/asset_files' # default: '{root_path}/app/assets'
22
- c.source_filter proc{ |paths| paths.select{ |p| ... } }
23
- # --OR--
24
- c.source 'lib/asset_files' do |paths|
25
- # return the filtered source path list
26
- paths.select{ |p| ... }
27
- end
17
+ # tell Dassets where to look for source files
18
+ c.source '/path/to/app/assets'
28
19
 
29
20
  # (optional) tell Dassets where to store digested asset files
30
21
  # if none given, Dassets will not write any digested output
31
22
  # use this to "cache" digested assets to the public dir (for example)
32
- c.file_store 'public' # default: `NullFileStore.new`
23
+ c.file_store '/path/to/public' # default: `NullFileStore.new`
33
24
 
34
25
  end
35
26
  ```
@@ -81,7 +72,7 @@ TODO: programmatically cache asset files
81
72
 
82
73
  ## Compiling
83
74
 
84
- Dassets can handle compiling your asset source as part of its digest pipeline. It does this via "engines". Engines transform source extensions and content.
75
+ Dassets compiles your asset source as part of its digest pipeline using "engines". Engines transform source extensions and content.
85
76
 
86
77
  Engines are "registered" with dassets based on source extensions. Name your source file with registered extensions and those engines will be used to compile your source content.
87
78
 
@@ -98,6 +89,10 @@ TODO
98
89
  * override the `compile` method to specify how the input content should be transformed
99
90
  * register your engine class with Dassets
100
91
 
92
+ ## Sources
93
+
94
+ TODO: filtering files, registering engines
95
+
101
96
  ## Combinations
102
97
 
103
98
  TODO
@@ -1,18 +1,18 @@
1
1
  require 'rack/utils'
2
2
  require 'rack/mime'
3
- require 'dassets/source_cache'
3
+ require 'dassets/source_proxy'
4
4
 
5
5
  module Dassets; end
6
6
  class Dassets::AssetFile
7
7
 
8
- attr_reader :digest_path, :dirname, :extname, :basename, :source_cache
8
+ attr_reader :digest_path, :dirname, :extname, :basename, :source_proxy
9
9
 
10
10
  def initialize(digest_path)
11
11
  @digest_path = digest_path
12
12
  @dirname = File.dirname(@digest_path)
13
13
  @extname = File.extname(@digest_path)
14
14
  @basename = File.basename(@digest_path, @extname)
15
- @source_cache = Dassets::SourceCache.new(@digest_path, Dassets.config.cache)
15
+ @source_proxy = Dassets::SourceProxy.new(@digest_path, Dassets.config.cache)
16
16
  end
17
17
 
18
18
  def digest!
@@ -33,17 +33,17 @@ class Dassets::AssetFile
33
33
 
34
34
  def fingerprint
35
35
  return nil if !self.exists?
36
- @fingerprint ||= @source_cache.fingerprint
36
+ @fingerprint ||= @source_proxy.fingerprint
37
37
  end
38
38
 
39
39
  def content
40
40
  return nil if !self.exists?
41
- @content ||= @source_cache.content
41
+ @content ||= @source_proxy.content
42
42
  end
43
43
 
44
44
  def mtime
45
45
  return nil if !self.exists?
46
- @mtime ||= @source_cache.mtime
46
+ @mtime ||= @source_proxy.mtime.httpdate
47
47
  end
48
48
 
49
49
  def size
@@ -57,7 +57,7 @@ class Dassets::AssetFile
57
57
  end
58
58
 
59
59
  def exists?
60
- @source_cache.exists?
60
+ @source_proxy.exists?
61
61
  end
62
62
 
63
63
  def ==(other_asset_file)
@@ -5,6 +5,11 @@ require 'dassets/source_file'
5
5
  module Dassets; end
6
6
  class Dassets::DigestCmd
7
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
+
8
13
  attr_reader :paths
9
14
 
10
15
  def initialize(abs_paths)
@@ -15,7 +20,7 @@ class Dassets::DigestCmd
15
20
  files = @paths
16
21
  if @paths.empty?
17
22
  # always get the latest source list
18
- files = Dassets::SourceList.new(Dassets.config)
23
+ files = Dassets.source_list
19
24
  end
20
25
 
21
26
  log io, "digesting #{files.count} source file(s) ..."
@@ -1,12 +1,11 @@
1
1
  require 'thread'
2
- require 'dassets/root_path'
3
2
 
4
3
  module Dassets; end
5
4
  class Dassets::FileStore
6
5
  attr_reader :root
7
6
 
8
7
  def initialize(root)
9
- @root = Dassets::RootPath.new(root)
8
+ @root = root
10
9
  @save_mutex = ::Mutex.new
11
10
  end
12
11
 
@@ -17,7 +17,7 @@ class Dassets::Server
17
17
  # - then check if for a digested asset resource (kinda fast)
18
18
  # - then check if source exists for the digested asset (slower)
19
19
  def for_asset_file?
20
- !!((get? || head?) && for_digested_asset? && asset_file.source_cache.exists?)
20
+ !!((get? || head?) && for_digested_asset? && asset_file.exists?)
21
21
  end
22
22
 
23
23
  def asset_path
@@ -0,0 +1,38 @@
1
+ require 'dassets/engine'
2
+
3
+ module Dassets; end
4
+ class Dassets::Source
5
+
6
+ attr_reader :path, :engines
7
+
8
+ def initialize(path)
9
+ @path = path.to_s
10
+ @filter = proc{ |paths| paths }
11
+ @engines = Hash.new{ |h,k| Dassets::NullEngine.new }
12
+ end
13
+
14
+ def filter(&block)
15
+ block.nil? ? @filter : @filter = block
16
+ end
17
+
18
+ def engine(input_ext, engine_class, registered_opts=nil)
19
+ default_opts = { 'source_path' => @path }
20
+ engine_opts = default_opts.merge(registered_opts || {})
21
+ @engines[input_ext.to_s] = engine_class.new(engine_opts)
22
+ end
23
+
24
+ def files
25
+ apply_filter(glob_files).sort
26
+ end
27
+
28
+ private
29
+
30
+ def glob_files
31
+ Dir.glob(File.join(@path, "**/*" )).reject!{ |p| !File.file?(p) }
32
+ end
33
+
34
+ def apply_filter(files)
35
+ @filter.call(files)
36
+ end
37
+
38
+ end
@@ -1,4 +1,3 @@
1
- require 'digest/md5'
2
1
  require 'fileutils'
3
2
  require 'dassets'
4
3
  require 'dassets/asset_file'
@@ -8,22 +7,30 @@ module Dassets
8
7
  class SourceFile
9
8
 
10
9
  def self.find_by_digest_path(path)
11
- # always look at the freshest source list to make sure you get all sources
12
- # not just the ones Dassets has cached
13
- sources = Dassets::SourceList.new(Dassets.config).map{ |p| self.new(p) }
10
+ # look in the configured source list
11
+ source_files = Dassets.source_list.map{ |p| self.new(p) }
14
12
 
15
- # get the last matching one in case two sources have the same digest path
16
- # the last one *should* be correct since it was last to be digested
17
- sources.select{ |s| s.digest_path == path }.last || NullSourceFile.new(path)
13
+ # get the last matching one (in case two source files have the same digest
14
+ # 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)
18
16
  end
19
17
 
20
18
  attr_reader :file_path
21
19
 
22
20
  def initialize(file_path)
23
- @file_path = file_path
21
+ @file_path = file_path.to_s
24
22
  @ext_list = File.basename(@file_path).split('.').reverse
25
23
  end
26
24
 
25
+ # get the last matching one (in the case two sources with the same path are
26
+ # configured) since we select the last matching source file (from the last
27
+ # configured source) in `find_by_digest_path` above.
28
+ def source
29
+ @source ||= Dassets.config.sources.select do |source|
30
+ @file_path =~ /^#{slash_path(source.path)}/
31
+ end.last
32
+ end
33
+
27
34
  def asset_file
28
35
  @asset_file ||= Dassets::AssetFile.new(self.digest_path)
29
36
  end
@@ -31,32 +38,25 @@ module Dassets
31
38
  def digest_path
32
39
  @digest_path ||= begin
33
40
  digest_basename = @ext_list.inject([]) do |digest_ext_list, ext|
34
- digest_ext_list << Dassets.config.engines[ext].ext(ext)
35
- end.reject{ |e| e.empty? }.reverse.join('.')
41
+ digest_ext_list << self.source.engines[ext].ext(ext)
42
+ end.reject(&:empty?).reverse.join('.')
36
43
 
37
- File.join([
38
- digest_dirname(@file_path, Dassets.config.source_path),
39
- digest_basename
40
- ].reject{ |p| p.empty? })
44
+ File.join([digest_dirname(@file_path), digest_basename].reject(&:empty?))
41
45
  end
42
46
  end
43
47
 
44
48
  def compiled
45
49
  @compiled ||= @ext_list.inject(read_file(@file_path)) do |content, ext|
46
- Dassets.config.engines[ext].compile(content)
50
+ self.source.engines[ext].compile(content)
47
51
  end
48
52
  end
49
53
 
50
- def fingerprint
51
- @fingerprint ||= Digest::MD5.new.hexdigest(self.compiled)
52
- end
53
-
54
54
  def exists?
55
55
  File.file?(@file_path)
56
56
  end
57
57
 
58
58
  def mtime
59
- File.mtime(@file_path).httpdate
59
+ File.mtime(@file_path)
60
60
  end
61
61
 
62
62
  def ==(other_source_file)
@@ -65,8 +65,9 @@ module Dassets
65
65
 
66
66
  private
67
67
 
68
- def digest_dirname(file_path, source_path)
69
- slash_path(File.dirname(file_path)).sub(slash_path(source_path), '')
68
+ # remove the source path from the dirname (if it exists)
69
+ def digest_dirname(file_path)
70
+ slash_path(File.dirname(file_path)).sub(slash_path(self.source.path), '')
70
71
  end
71
72
 
72
73
  def slash_path(path)
@@ -86,7 +87,6 @@ module Dassets
86
87
  @ext_list = []
87
88
  @digest_path = digest_path
88
89
  end
89
- def digest; end
90
90
  def ==(other_source_file)
91
91
  self.file_path == other_source_file.file_path
92
92
  end
@@ -0,0 +1,56 @@
1
+ require 'digest/md5'
2
+ require 'dassets/source_file'
3
+
4
+ module Dassets; end
5
+ class Dassets::SourceProxy
6
+
7
+ attr_reader :digest_path, :source_files, :cache
8
+
9
+ def initialize(digest_path, cache=nil)
10
+ @digest_path = digest_path
11
+ @source_files = get_source_files(@digest_path)
12
+ @cache = cache || NoCache.new
13
+ end
14
+
15
+ def key
16
+ "#{self.digest_path} -- #{self.mtime}"
17
+ end
18
+
19
+ def content
20
+ @cache["#{self.key} -- content"] ||= source_content
21
+ end
22
+
23
+ def fingerprint
24
+ @cache["#{self.key} -- fingerprint"] ||= source_fingerprint
25
+ end
26
+
27
+ def mtime
28
+ @source_files.map{ |f| f.mtime }.max
29
+ end
30
+
31
+ def exists?
32
+ @source_files.inject(true){ |res, f| res && f.exists? }
33
+ end
34
+
35
+ private
36
+
37
+ def source_content
38
+ @source_content ||= @source_files.map{ |f| f.compiled }.join("\n")
39
+ end
40
+
41
+ def source_fingerprint
42
+ @source_fingerprint ||= Digest::MD5.new.hexdigest(source_content)
43
+ end
44
+
45
+ def get_source_files(digest_path)
46
+ Dassets.config.combinations[digest_path.to_s].map do |source_digest_path|
47
+ Dassets::SourceFile.find_by_digest_path(source_digest_path)
48
+ end
49
+ end
50
+
51
+ class NoCache
52
+ def [](key); end
53
+ def []=(key, value); end
54
+ end
55
+
56
+ end
@@ -1,3 +1,3 @@
1
1
  module Dassets
2
- VERSION = "0.5.0"
2
+ VERSION = "0.6.0"
3
3
  end
data/lib/dassets.rb CHANGED
@@ -3,10 +3,9 @@ require 'set'
3
3
  require 'ns-options'
4
4
 
5
5
  require 'dassets/version'
6
- require 'dassets/root_path'
7
6
  require 'dassets/file_store'
8
7
  require 'dassets/default_cache'
9
- require 'dassets/engine'
8
+ require 'dassets/source'
10
9
  require 'dassets/asset_file'
11
10
 
12
11
  ENV['DASSETS_ASSETS_FILE'] ||= 'config/assets'
@@ -23,13 +22,16 @@ module Dassets
23
22
  require self.config.assets_file
24
23
  rescue LoadError
25
24
  end
26
- raise 'no Dassets `root_path` specified' if !self.config.required_set?
27
25
  end
28
26
 
29
27
  def self.[](digest_path)
30
28
  AssetFile.new(digest_path)
31
29
  end
32
30
 
31
+ def self.source_list
32
+ SourceList.new(self.config.sources)
33
+ end
34
+
33
35
  # Cmds
34
36
 
35
37
  def self.digest_source_files(paths=nil)
@@ -40,38 +42,31 @@ module Dassets
40
42
  class Config
41
43
  include NsOptions::Proxy
42
44
 
43
- option :root_path, Pathname, :required => true
44
45
  option :assets_file, Pathname, :default => ENV['DASSETS_ASSETS_FILE']
45
- option :source_path, RootPath, :default => proc{ "app/assets" }
46
- option :source_filter, Proc, :default => proc{ |paths| paths }
47
46
  option :file_store, FileStore, :default => proc{ NullFileStore.new }
48
47
 
49
- attr_reader :engines
48
+ attr_reader :sources, :combinations
50
49
  attr_accessor :cache
51
50
 
52
51
  def initialize
53
52
  super
54
- @engines = Hash.new{ |k,v| Dassets::NullEngine.new }
53
+ @sources = []
54
+ @combinations = Hash.new{ |h,k| [k] } # digest pass-thru if none defined
55
55
  @cache = DefaultCache.new
56
56
  end
57
57
 
58
- def source(path=nil, &filter)
59
- self.source_path = path if path
60
- self.source_filter = filter if filter
58
+ def source(path, &block)
59
+ @sources << Source.new(path).tap{ |s| block.call(s) if block }
61
60
  end
62
61
 
63
- def engine(input_ext, engine_class, opts=nil)
64
- @engines[input_ext.to_s] = engine_class.new(opts)
62
+ def combination(key_digest_path, value_digest_paths)
63
+ @combinations[key_digest_path.to_s] = [*value_digest_paths]
65
64
  end
66
65
  end
67
66
 
68
67
  module SourceList
69
- def self.new(config)
70
- paths = Set.new
71
- paths += Dir.glob(File.join(config.source_path, "**/*"))
72
- paths.reject!{ |path| !File.file?(path) }
73
-
74
- config.source_filter.call(paths).sort
68
+ def self.new(sources)
69
+ sources.inject([]){ |list, source| list += source.files }
75
70
  end
76
71
  end
77
72
 
data/test/helper.rb CHANGED
@@ -7,6 +7,9 @@ $LOAD_PATH.unshift(File.expand_path("../..", __FILE__))
7
7
  # require pry for debugging (`binding.pry`)
8
8
  require 'pry'
9
9
 
10
+ require 'pathname'
11
+ TEST_SUPPORT_PATH = Pathname.new(File.expand_path('../support', __FILE__))
12
+
10
13
  ENV['DASSETS_TEST_MODE'] = 'yes'
11
14
  ENV['DASSETS_ASSETS_FILE'] = 'test/support/config/assets'
12
15
  require 'dassets'
@@ -10,10 +10,11 @@ end
10
10
  end
11
11
 
12
12
  Dassets.configure do |c|
13
- c.root_path File.expand_path("../..", __FILE__)
13
+ c.source TEST_SUPPORT_PATH.join("app/assets") do |s|
14
+ s.engine 'dumb', @dumb_engine
15
+ s.engine 'useless', @useless_engine
16
+ end
14
17
 
15
- c.engine 'dumb', @dumb_engine
16
- c.engine 'useless', @useless_engine
17
18
  c.cache = nil # use no cache
18
19
 
19
20
  end
@@ -7,7 +7,7 @@ module Dassets
7
7
  class DigestCmdRunTests < Assert::Context
8
8
  desc "the DigestCmd"
9
9
  setup do
10
- Dassets.config.file_store = 'public'
10
+ Dassets.config.file_store = TEST_SUPPORT_PATH.join('public').to_s
11
11
  clear_store_path(Dassets.config.file_store.root)
12
12
  Dassets.digest_source_files
13
13
 
@@ -52,7 +52,7 @@ module Dassets
52
52
  private
53
53
 
54
54
  def source_path(file)
55
- File.join(File.join(Dassets.config.source_path, file))
55
+ File.join(Dassets.config.sources.first.path, file)
56
56
  end
57
57
 
58
58
  def store_path(file)
@@ -40,7 +40,7 @@ module Dassets
40
40
 
41
41
  class DigestTests < SuccessTests
42
42
  setup do
43
- Dassets.config.file_store = 'public'
43
+ Dassets.config.file_store = TEST_SUPPORT_PATH.join('public').to_s
44
44
  @url = 'file1-daa05c683a4913b268653f7a7e36a5b4.txt'
45
45
  @url_file = Dassets.config.file_store.store_path(@url)
46
46
  FileUtils.rm(@url_file)
@@ -1,7 +1,7 @@
1
1
  require 'assert'
2
2
  require 'fileutils'
3
3
  require 'dassets/file_store'
4
- require 'dassets/source_cache'
4
+ require 'dassets/source_proxy'
5
5
  require 'dassets/asset_file'
6
6
 
7
7
  class Dassets::AssetFile
@@ -13,7 +13,7 @@ class Dassets::AssetFile
13
13
  end
14
14
  subject{ @asset_file }
15
15
 
16
- should have_readers :digest_path, :dirname, :extname, :basename, :source_cache
16
+ should have_readers :digest_path, :dirname, :extname, :basename, :source_proxy
17
17
  should have_imeths :digest!, :url, :fingerprint, :content
18
18
  should have_imeths :href, :mtime, :size, :mime_type, :exists?, :==
19
19
 
@@ -25,7 +25,7 @@ class Dassets::AssetFile
25
25
  end
26
26
 
27
27
  should "use its source file attrs as its own" do
28
- assert_equal subject.source_cache.mtime, subject.mtime
28
+ assert_equal subject.source_proxy.mtime.httpdate, subject.mtime
29
29
  assert_equal Rack::Utils.bytesize(subject.content), subject.size
30
30
  assert_equal "text/plain", subject.mime_type
31
31
  assert subject.exists?
@@ -37,19 +37,19 @@ class Dassets::AssetFile
37
37
  assert_not null_file.exists?
38
38
  end
39
39
 
40
- should "know its source cache" do
41
- assert_not_nil subject.source_cache
42
- assert_kind_of Dassets::SourceCache, subject.source_cache
43
- assert_equal subject.digest_path, subject.source_cache.digest_path
40
+ should "know its source proxy" do
41
+ assert_not_nil subject.source_proxy
42
+ assert_kind_of Dassets::SourceProxy, subject.source_proxy
43
+ assert_equal subject.digest_path, subject.source_proxy.digest_path
44
44
  end
45
45
 
46
46
  should "have a fingerprint" do
47
47
  assert_not_nil subject.fingerprint
48
48
  end
49
49
 
50
- should "get its fingerprint from its source cache if none is given" do
50
+ should "get its fingerprint from its source proxy if none is given" do
51
51
  af = Dassets::AssetFile.new('file1.txt')
52
- assert_equal af.source_cache.fingerprint, af.fingerprint
52
+ assert_equal af.source_proxy.fingerprint, af.fingerprint
53
53
  end
54
54
 
55
55
  should "know it's content" do
@@ -59,7 +59,7 @@ class Dassets::AssetFile
59
59
  assert_nil null_file.content
60
60
  end
61
61
 
62
- should "get its content from its source cache if no output file" do
62
+ should "get its content from its source proxy if no output file" do
63
63
  digest_path = 'nested/a-thing.txt.no-use'
64
64
  exp_content = "thing\n\nDUMB\nUSELESS"
65
65
 
@@ -86,7 +86,7 @@ class Dassets::AssetFile
86
86
  class DigestTests < BaseTests
87
87
  desc "being digested with an output path configured"
88
88
  setup do
89
- Dassets.config.file_store = 'public'
89
+ Dassets.config.file_store = TEST_SUPPORT_PATH.join('public').to_s
90
90
  @save_path = @asset_file.digest!
91
91
  @outfile = Dassets.config.file_store.store_path(@asset_file.url)
92
92
  end
@@ -12,46 +12,37 @@ class Dassets::Config
12
12
  end
13
13
  subject{ @config }
14
14
 
15
- should have_option :root_path, Pathname, :required => true
16
- should have_option :assets_file, Pathname, :default => ENV['DASSETS_ASSETS_FILE']
17
- should have_options :source_path, :source_filter, :file_store
15
+ should have_option :assets_file, Pathname, :default => ENV['DASSETS_ASSETS_FILE']
16
+ should have_options :file_store
18
17
 
19
- should have_reader :engines
20
- should have_imeth :source, :engine
18
+ should have_reader :combinations
19
+ should have_imeth :source, :combination
21
20
 
22
- should "should use `apps/assets` as the default source path" do
23
- exp_path = Dassets.config.root_path.join("app/assets").to_s
24
- assert_equal exp_path, subject.source_path
25
- end
26
-
27
- should "set the source path and filter proc with the `sources` method" do
28
- path = Dassets::RootPath.new 'app/asset_files'
21
+ should "register new sources with the `source` method" do
22
+ path = '/path/to/app/assets'
29
23
  filter = proc{ |paths| [] }
24
+ subject.source(path){ |s| s.filter(&filter) }
30
25
 
31
- subject.source(path, &filter)
32
- assert_equal path, subject.source_path
33
- assert_equal filter, subject.source_filter
26
+ assert_equal 1, subject.sources.size
27
+ assert_kind_of Dassets::Source, subject.sources.first
28
+ assert_equal path, subject.sources.first.path
29
+ assert_equal filter, subject.sources.first.filter
34
30
  end
35
31
 
36
- should "know its engines and return a NullEngine by default" do
37
- assert_kind_of ::Hash, subject.engines
38
- assert_kind_of Dassets::NullEngine, subject.engines['some']
39
- assert_kind_of Dassets::NullEngine, subject.engines['thing']
32
+ should "know its combinations and return the keyed digest path by default" do
33
+ assert_kind_of ::Hash, subject.combinations
34
+ assert_equal ['some/digest.path'], subject.combinations['some/digest.path']
40
35
  end
41
36
 
42
- should "allow registering new engines" do
43
- empty_engine = Class.new(Dassets::Engine) do
44
- def ext(input_ext); ''; end
45
- def compile(input); ''; end
46
- end
47
-
48
- assert_kind_of Dassets::NullEngine, subject.engines['empty']
49
- subject.engine 'empty', empty_engine, 'an' => 'opt'
50
- assert_kind_of empty_engine, subject.engines['empty']
37
+ should "allow registering new combinations" do
38
+ assert_equal ['some/digest.path'], subject.combinations['some/digest.path']
39
+ exp_combination = ['some/other.path', 'and/another.path']
40
+ subject.combination 'some/digest.path', exp_combination
41
+ assert_equal exp_combination, subject.combinations['some/digest.path']
51
42
 
52
- assert_equal({'an' => 'opt'}, subject.engines['empty'].opts)
53
- assert_equal '', subject.engines['empty'].ext('empty')
54
- assert_equal '', subject.engines['empty'].compile('some content')
43
+ assert_equal ['test/digest.path'], subject.combinations['test/digest.path']
44
+ subject.combination 'test/digest.path', ['some/other.path']
45
+ assert_equal ['some/other.path'], subject.combinations['test/digest.path']
55
46
  end
56
47
 
57
48
  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 :digest_source_files
12
+ should have_imeths :source_list, :digest_source_files
13
13
 
14
14
  should "return a `Config` instance with the `config` method" do
15
15
  assert_kind_of Config, subject.config
@@ -23,54 +23,14 @@ module Dassets
23
23
  assert_equal 'd41d8cd98f00b204e9800998ecf8427e', file.fingerprint
24
24
  end
25
25
 
26
- should "return an asset file with unknown source if digest path not found" do
26
+ should "return an asset file that doesn't exist if digest path not found" do
27
27
  file = subject['path/not/found.txt']
28
-
29
- assert_kind_of Dassets::SourceCache, file.source_cache
30
- assert_kind_of Dassets::NullSourceFile, file.source_cache.source_file
31
- assert_not file.source_cache.exists?
28
+ assert_not file.exists?
32
29
  end
33
30
 
34
- should "complain if trying to init without setting the root path" do
35
- orig_root = Dassets.config.root_path
36
-
37
- Dassets.config.root_path = nil
38
- assert_raises(RuntimeError){ Dassets.init }
39
-
40
- Dassets.config.root_path = orig_root
41
- end
42
-
43
- end
44
-
45
- class SourceListTests < BaseTests
46
- desc "source list"
47
-
48
- should "build from the configured source path and filter proc" do
49
- config = Dassets::Config.new
50
- config.source_path = "source_files" # test/support/source_files
51
- exp_list = [
52
- 'test1.txt', '_ignored.txt', 'nested/test2.txt', 'nested/_nested_ignored.txt'
53
- ].map{ |p| File.expand_path(p, config.source_path) }.sort
54
-
55
- assert_equal exp_list, Dassets::SourceList.new(config)
56
- end
57
-
58
- should "run the supplied source filter on the paths" do
59
- config = Dassets::Config.new
60
- config.source_path = "source_files" # test/support/source_files
61
- config.source_filter = proc do |paths|
62
- paths.reject{ |path| File.basename(path) =~ /^_/ }
63
- end
64
- exp_list = [
65
- 'test1.txt', 'nested/test2.txt'
66
- ].map{ |p| File.expand_path(p, config.source_path) }.sort
67
-
68
- assert_equal exp_list, Dassets::SourceList.new(config)
69
-
70
- config.source "source_files" do |paths|
71
- paths.reject{ |path| File.basename(path) =~ /^_/ }
72
- end
73
- assert_equal exp_list, Dassets::SourceList.new(config)
31
+ should "know its list of configured source files" do
32
+ exp_configured_list = Dassets::SourceList.new(Dassets.config.sources)
33
+ assert_equal exp_configured_list, subject.source_list
74
34
  end
75
35
 
76
36
  end
@@ -1,10 +1,9 @@
1
1
  require 'assert'
2
- require 'dassets/root_path'
3
2
  require 'dassets/file_store'
4
3
 
5
4
  class Dassets::FileStore
6
5
 
7
- class BaseTests < Assert::Context
6
+ class NullTests < Assert::Context
8
7
  desc "Dassets::NullFileStore"
9
8
  subject{ Dassets::NullFileStore.new }
10
9
 
@@ -15,14 +14,16 @@ class Dassets::FileStore
15
14
  assert_kind_of Dassets::FileStore, subject
16
15
  end
17
16
 
18
- should "build its root based on the config's root_path" do
19
- assert_equal Dassets::RootPath.new(''), subject.root
17
+ should "know its root path" do
18
+ assert_equal '', subject.root
20
19
  end
21
20
 
22
21
  should "build the store path based on a given url" do
22
+ assert_equal '/some/url', subject.store_path('some/url')
23
23
  end
24
24
 
25
25
  should "return the store path on save" do
26
+ assert_equal '/some/url', subject.save('some/url')
26
27
  end
27
28
 
28
29
  end
@@ -7,18 +7,18 @@ class Dassets::SourceFile
7
7
  class BaseTests < Assert::Context
8
8
  desc "Dassets::SourceFile"
9
9
  setup do
10
- @file_path = File.join(Dassets.config.source_path, 'file1.txt')
10
+ @file_path = TEST_SUPPORT_PATH.join('app/assets/file1.txt').to_s
11
11
  @source_file = Dassets::SourceFile.new(@file_path)
12
12
  end
13
13
  subject{ @source_file }
14
14
 
15
15
  should have_readers :file_path
16
- should have_imeths :asset_file, :digest_path
17
- should have_imeths :compiled, :fingerprint, :exists?, :mtime
16
+ should have_imeths :source, :asset_file, :digest_path
17
+ should have_imeths :compiled, :exists?, :mtime
18
18
  should have_cmeth :find_by_digest_path
19
19
 
20
20
  should "know its file path" do
21
- assert_equal @file_path, subject.file_path
21
+ assert_equal @file_path.to_s, subject.file_path
22
22
  end
23
23
 
24
24
  should "know if it exists" do
@@ -26,7 +26,7 @@ class Dassets::SourceFile
26
26
  end
27
27
 
28
28
  should "use the mtime of its file as its mtime" do
29
- assert_equal File.mtime(subject.file_path).httpdate, subject.mtime
29
+ assert_equal File.mtime(subject.file_path), subject.mtime
30
30
  end
31
31
 
32
32
  should "know its digest path" do
@@ -38,8 +38,9 @@ class Dassets::SourceFile
38
38
  assert_equal Dassets::AssetFile.new(subject.digest_path), subject.asset_file
39
39
  end
40
40
 
41
- should "know its compiled content fingerprint" do
42
- assert_equal 'daa05c683a4913b268653f7a7e36a5b4', subject.fingerprint
41
+ should "know its configured source" do
42
+ exp_source = Dassets.config.sources.select{ |s| @file_path.include?(s.path) }.last
43
+ assert_equal exp_source, subject.source
43
44
  end
44
45
 
45
46
  should "be findable by its digest path" do
@@ -62,7 +63,7 @@ class Dassets::SourceFile
62
63
  class EngineTests < BaseTests
63
64
  desc "compiled against engines"
64
65
  setup do
65
- @file_path = File.join(Dassets.config.source_path, 'nested/a-thing.txt.useless.dumb')
66
+ @file_path = TEST_SUPPORT_PATH.join('app/assets/nested/a-thing.txt.useless.dumb')
66
67
  @source_file = Dassets::SourceFile.new(@file_path)
67
68
  end
68
69
 
@@ -0,0 +1,92 @@
1
+ require 'assert'
2
+ require 'digest/md5'
3
+ require 'dassets/source_file'
4
+ require 'dassets/source_proxy'
5
+
6
+ class Dassets::SourceProxy
7
+
8
+ class BaseTests < Assert::Context
9
+ desc "Dassets::SourceProxy"
10
+ setup do
11
+ @source_proxy = Dassets::SourceProxy.new('file1.txt')
12
+ end
13
+ subject{ @source_proxy }
14
+
15
+ should have_readers :digest_path, :source_files
16
+ should have_imeths :content, :fingerprint, :key, :mtime, :exists?
17
+
18
+ should "know its digest path" do
19
+ assert_equal 'file1.txt', subject.digest_path
20
+ end
21
+
22
+ should "know its source file" do
23
+ exp_source_file = Dassets::SourceFile.find_by_digest_path('file1.txt')
24
+ assert_equal 1, subject.source_files.size
25
+ assert_equal exp_source_file, subject.source_files.first
26
+ end
27
+
28
+ should "exist if its source file exists" do
29
+ assert_equal subject.source_files.first.exists?, subject.exists?
30
+ end
31
+
32
+ should "use its source file's mtime as its mtime" do
33
+ assert_equal subject.source_files.first.mtime, subject.mtime
34
+ end
35
+
36
+ should "use its digest path and mtime as its key" do
37
+ exp_key = "#{subject.digest_path} -- #{subject.mtime}"
38
+ assert_equal exp_key, subject.key
39
+ end
40
+
41
+ should "get its fingerprint by MD5 hashing the compiled source" do
42
+ exp_fp = Digest::MD5.new.hexdigest(subject.content)
43
+ assert_equal exp_fp, subject.fingerprint
44
+ end
45
+
46
+ should "get its content from the compiled source" do
47
+ assert_equal subject.source_files.first.compiled, subject.content
48
+ end
49
+
50
+ end
51
+
52
+ class CombinationTests < BaseTests
53
+ desc "when the digest path is a combination to multiple source files"
54
+ setup do
55
+ Dassets.config.combination 'file3.txt', ['file1.txt', 'file2.txt']
56
+ @source_proxy = Dassets::SourceProxy.new('file3.txt')
57
+ @exp_source_files = [
58
+ Dassets::SourceFile.find_by_digest_path('file1.txt'),
59
+ Dassets::SourceFile.find_by_digest_path('file2.txt')
60
+ ]
61
+ end
62
+ teardown do
63
+ Dassets.config.combinations.delete('file3.txt')
64
+ end
65
+
66
+ should "know its digest path" do
67
+ assert_equal 'file3.txt', subject.digest_path
68
+ end
69
+
70
+ should "know its source file" do
71
+ assert_equal 2, subject.source_files.size
72
+ assert_equal @exp_source_files, subject.source_files
73
+ end
74
+
75
+ should "exist if its source file exists" do
76
+ exp_exists = @exp_source_files.inject(true){ |res, f| res && f.exists? }
77
+ assert_equal exp_exists, subject.exists?
78
+ end
79
+
80
+ should "use its source file's mtime as its mtime" do
81
+ exp_mtime = @exp_source_files.map{ |f| f.mtime }.max
82
+ assert_equal exp_mtime, subject.mtime
83
+ end
84
+
85
+ should "get its content from the compiled source" do
86
+ exp_content = @exp_source_files.map{ |f| f.compiled }.join("\n")
87
+ assert_equal exp_content, subject.content
88
+ end
89
+
90
+ end
91
+
92
+ end
@@ -0,0 +1,89 @@
1
+ require 'assert'
2
+ require 'dassets/source'
3
+
4
+ class Dassets::Source
5
+
6
+ class BaseTests < Assert::Context
7
+ desc "Dassets::Source"
8
+ setup do
9
+ @source_path = TEST_SUPPORT_PATH.join("source_files")
10
+ @source = Dassets::Source.new(@source_path)
11
+ end
12
+ subject{ @source }
13
+
14
+ should have_reader :path, :engines
15
+ should have_imeth :files, :filter, :engine
16
+
17
+ should "know its path and default filter" do
18
+ assert_equal @source_path.to_s, subject.path
19
+ assert_kind_of Proc, subject.filter
20
+ assert_equal ['file1', 'file2'], subject.filter.call(['file1', 'file2'])
21
+ end
22
+
23
+ should "know its files" do
24
+ exp_files = [
25
+ @source_path.join('test1.txt').to_s,
26
+ @source_path.join('_ignored.txt').to_s,
27
+ @source_path.join('nested/test2.txt').to_s,
28
+ @source_path.join('nested/_nested_ignored.txt').to_s
29
+ ].sort
30
+ assert_equal exp_files, subject.files
31
+ end
32
+
33
+ should "run the supplied source filter on the paths" do
34
+ subject.filter do |paths|
35
+ paths.reject{ |path| File.basename(path) =~ /^_/ }
36
+ end
37
+ exp_files = [
38
+ @source_path.join('test1.txt').to_s,
39
+ @source_path.join('nested/test2.txt').to_s,
40
+ ].sort
41
+
42
+ assert_equal exp_files, subject.files
43
+ end
44
+
45
+ should "know its engines and return a NullEngine by default" do
46
+ assert_kind_of ::Hash, subject.engines
47
+ assert_kind_of Dassets::NullEngine, subject.engines['something']
48
+ end
49
+
50
+ end
51
+
52
+ class EngineRegistrationTests < BaseTests
53
+ desc "when registering an engine"
54
+ setup do
55
+ @empty_engine = Class.new(Dassets::Engine) do
56
+ def ext(input_ext); ''; end
57
+ def compile(input); ''; end
58
+ end
59
+ end
60
+
61
+ should "allow registering new engines" do
62
+ assert_kind_of Dassets::NullEngine, subject.engines['empty']
63
+ subject.engine 'empty', @empty_engine, 'an' => 'opt'
64
+ assert_kind_of @empty_engine, subject.engines['empty']
65
+ assert_equal 'opt', subject.engines['empty'].opts['an']
66
+ assert_equal '', subject.engines['empty'].ext('empty')
67
+ assert_equal '', subject.engines['empty'].compile('some content')
68
+ end
69
+
70
+ should "register with the source path as a default option" do
71
+ subject.engine 'empty', @empty_engine
72
+ exp_opts = { 'source_path' => subject.path }
73
+ assert_equal exp_opts, subject.engines['empty'].opts
74
+
75
+ subject.engine 'empty', @empty_engine, 'an' => 'opt'
76
+ exp_opts = {
77
+ 'source_path' => subject.path,
78
+ 'an' => 'opt'
79
+ }
80
+ assert_equal exp_opts, subject.engines['empty'].opts
81
+
82
+ subject.engine 'empty', @empty_engine, 'source_path' => 'something'
83
+ exp_opts = { 'source_path' => 'something' }
84
+ assert_equal exp_opts, subject.engines['empty'].opts
85
+ end
86
+
87
+ end
88
+
89
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dassets
3
3
  version: !ruby/object:Gem::Version
4
- hash: 11
4
+ hash: 7
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 5
8
+ - 6
9
9
  - 0
10
- version: 0.5.0
10
+ version: 0.6.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-05-02 00:00:00 Z
19
+ date: 2013-05-09 00:00:00 Z
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
22
  name: assert
@@ -118,13 +118,13 @@ files:
118
118
  - lib/dassets/digest_cmd.rb
119
119
  - lib/dassets/engine.rb
120
120
  - lib/dassets/file_store.rb
121
- - lib/dassets/root_path.rb
122
121
  - lib/dassets/runner.rb
123
122
  - lib/dassets/server.rb
124
123
  - lib/dassets/server/request.rb
125
124
  - lib/dassets/server/response.rb
126
- - lib/dassets/source_cache.rb
125
+ - lib/dassets/source.rb
127
126
  - lib/dassets/source_file.rb
127
+ - lib/dassets/source_proxy.rb
128
128
  - lib/dassets/version.rb
129
129
  - log/.gitkeep
130
130
  - test/helper.rb
@@ -157,8 +157,9 @@ files:
157
157
  - test/unit/server/request_tests.rb
158
158
  - test/unit/server/response_tests.rb
159
159
  - test/unit/server_tests.rb
160
- - test/unit/source_cache_tests.rb
161
160
  - test/unit/source_file_tests.rb
161
+ - test/unit/source_proxy_tests.rb
162
+ - test/unit/source_tests.rb
162
163
  - tmp/.gitkeep
163
164
  homepage: http://github.com/redding/dassets
164
165
  licenses: []
@@ -224,5 +225,6 @@ test_files:
224
225
  - test/unit/server/request_tests.rb
225
226
  - test/unit/server/response_tests.rb
226
227
  - test/unit/server_tests.rb
227
- - test/unit/source_cache_tests.rb
228
228
  - test/unit/source_file_tests.rb
229
+ - test/unit/source_proxy_tests.rb
230
+ - test/unit/source_tests.rb
@@ -1,12 +0,0 @@
1
- # This takes a path string relative to the configured root path and tranforms
2
- # to the full qualifed root path. The goal here is to specify path options
3
- # with root-relative path strings.
4
-
5
- module Dassets; end
6
- class Dassets::RootPath < String
7
-
8
- def initialize(path_string)
9
- super(Dassets.config.root_path.join(path_string).to_s)
10
- end
11
-
12
- end
@@ -1,39 +0,0 @@
1
- require 'dassets/source_file'
2
-
3
- module Dassets; end
4
- class Dassets::SourceCache
5
-
6
- attr_reader :digest_path, :source_file, :cache
7
-
8
- def initialize(digest_path, cache=nil)
9
- @digest_path = digest_path
10
- @source_file = Dassets::SourceFile.find_by_digest_path(digest_path)
11
- @cache = cache || NoCache.new
12
- end
13
-
14
- def content
15
- @cache["#{self.key} -- content"] ||= @source_file.compiled
16
- end
17
-
18
- def fingerprint
19
- @cache["#{self.key} -- fingerprint"] ||= @source_file.fingerprint
20
- end
21
-
22
- def key
23
- "#{self.digest_path} -- #{self.mtime}"
24
- end
25
-
26
- def mtime
27
- @source_file.mtime
28
- end
29
-
30
- def exists?
31
- @source_file.exists?
32
- end
33
-
34
- class NoCache
35
- def [](key); end
36
- def []=(key, value); end
37
- end
38
-
39
- end
@@ -1,50 +0,0 @@
1
- require 'assert'
2
- require 'dassets/source_file'
3
- require 'dassets/source_cache'
4
-
5
- class Dassets::SourceCache
6
-
7
- class BaseTests < Assert::Context
8
- desc "Dassets::SourceCache"
9
- setup do
10
- @source_cache = Dassets::SourceCache.new('file1.txt')
11
- end
12
- subject{ @source_cache }
13
-
14
- should have_readers :digest_path, :source_file
15
- should have_imeths :content, :fingerprint, :key, :mtime, :exists?
16
-
17
- should "know its digest path" do
18
- assert_equal 'file1.txt', subject.digest_path
19
- end
20
-
21
- should "know its source file" do
22
- exp_source_file = Dassets::SourceFile.find_by_digest_path('file1.txt')
23
- assert_equal exp_source_file, subject.source_file
24
- end
25
-
26
- should "exist if its source file exists" do
27
- assert_equal subject.source_file.exists?, subject.exists?
28
- end
29
-
30
- should "use its source file's mtime as its mtime" do
31
- assert_equal subject.source_file.mtime, subject.mtime
32
- end
33
-
34
- should "use its digest path and mtime as its key" do
35
- exp_key = "#{subject.digest_path} -- #{subject.mtime}"
36
- assert_equal exp_key, subject.key
37
- end
38
-
39
- should "get its fingerprint from the source file" do
40
- assert_equal subject.source_file.fingerprint, subject.fingerprint
41
- end
42
-
43
- should "get its content from the source file" do
44
- assert_equal subject.source_file.compiled, subject.content
45
- end
46
-
47
-
48
- end
49
-
50
- end