dassets 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. data/README.md +42 -10
  2. data/lib/dassets.rb +16 -28
  3. data/lib/dassets/asset_file.rb +36 -33
  4. data/lib/dassets/default_cache.rb +29 -0
  5. data/lib/dassets/digest_cmd.rb +36 -0
  6. data/lib/dassets/engine.rb +0 -2
  7. data/lib/dassets/file_store.rb +36 -0
  8. data/lib/dassets/runner.rb +2 -9
  9. data/lib/dassets/server/request.rb +5 -5
  10. data/lib/dassets/source_cache.rb +39 -0
  11. data/lib/dassets/source_file.rb +37 -13
  12. data/lib/dassets/version.rb +1 -1
  13. data/test/support/config/assets.rb +1 -0
  14. data/test/system/digest_cmd_run_tests.rb +37 -39
  15. data/test/system/rack_tests.rb +3 -7
  16. data/test/unit/asset_file_tests.rb +72 -40
  17. data/test/unit/config_tests.rb +3 -17
  18. data/test/unit/dassets_tests.rb +8 -42
  19. data/test/unit/default_cache_tests.rb +27 -0
  20. data/test/unit/{cmds/digest_cmd_tests.rb → digest_cmd_tests.rb} +4 -4
  21. data/test/unit/file_store_tests.rb +30 -0
  22. data/test/unit/server/request_tests.rb +7 -11
  23. data/test/unit/server/response_tests.rb +4 -5
  24. data/test/unit/source_cache_tests.rb +50 -0
  25. data/test/unit/source_file_tests.rb +28 -29
  26. metadata +16 -31
  27. data/lib/dassets/cmds/cache_cmd.rb +0 -33
  28. data/lib/dassets/cmds/digest_cmd.rb +0 -53
  29. data/lib/dassets/digests.rb +0 -61
  30. data/test/support/app/assets/.digests +0 -5
  31. data/test/support/app/assets/public/file1.txt +0 -1
  32. data/test/support/app/assets/public/file2.txt +0 -1
  33. data/test/support/app/assets/public/grumpy_cat.jpg +0 -0
  34. data/test/support/app/assets/public/nested/a-thing.txt.no-use +0 -4
  35. data/test/support/app/assets/public/nested/file3.txt +0 -0
  36. data/test/support/app_public/.gitkeep +0 -0
  37. data/test/support/example.digests +0 -3
  38. data/test/system/cache_cmd_run_tests.rb +0 -27
  39. data/test/unit/cmds/cache_cmd_tests.rb +0 -33
  40. data/test/unit/digests_tests.rb +0 -79
@@ -7,6 +7,16 @@ module Dassets
7
7
 
8
8
  class SourceFile
9
9
 
10
+ 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) }
14
+
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)
18
+ end
19
+
10
20
  attr_reader :file_path
11
21
 
12
22
  def initialize(file_path)
@@ -14,19 +24,8 @@ module Dassets
14
24
  @ext_list = File.basename(@file_path).split('.').reverse
15
25
  end
16
26
 
17
- def exists?
18
- File.file?(@file_path)
19
- end
20
-
21
- def digest
22
- return if !self.exists?
23
-
24
- Dassets::AssetFile.new(self.digest_path, self.fingerprint).tap do |asset_file|
25
- FileUtils.mkdir_p(File.dirname(asset_file.output_path))
26
- File.open(asset_file.output_path, "w"){ |f| f.write(self.compiled) }
27
- Dassets.digests[self.digest_path] = self.fingerprint
28
- Dassets.digests.save!
29
- end
27
+ def asset_file
28
+ @asset_file ||= Dassets::AssetFile.new(self.digest_path)
30
29
  end
31
30
 
32
31
  def digest_path
@@ -52,6 +51,18 @@ module Dassets
52
51
  @fingerprint ||= Digest::MD5.new.hexdigest(self.compiled)
53
52
  end
54
53
 
54
+ def exists?
55
+ File.file?(@file_path)
56
+ end
57
+
58
+ def mtime
59
+ File.mtime(@file_path).httpdate
60
+ end
61
+
62
+ def ==(other_source_file)
63
+ self.file_path == other_source_file.file_path
64
+ end
65
+
55
66
  private
56
67
 
57
68
  def digest_dirname(file_path, source_path)
@@ -68,4 +79,17 @@ module Dassets
68
79
 
69
80
  end
70
81
 
82
+ class NullSourceFile < SourceFile
83
+ attr_reader :file_path, :digest_path, :compiled, :fingerprint
84
+ def initialize(digest_path)
85
+ @file_path = ''
86
+ @ext_list = []
87
+ @digest_path = digest_path
88
+ end
89
+ def digest; end
90
+ def ==(other_source_file)
91
+ self.file_path == other_source_file.file_path
92
+ end
93
+ end
94
+
71
95
  end
@@ -1,3 +1,3 @@
1
1
  module Dassets
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -14,5 +14,6 @@ Dassets.configure do |c|
14
14
 
15
15
  c.engine 'dumb', @dumb_engine
16
16
  c.engine 'useless', @useless_engine
17
+ c.cache = nil # use no cache
17
18
 
18
19
  end
@@ -7,62 +7,60 @@ module Dassets
7
7
  class DigestCmdRunTests < Assert::Context
8
8
  desc "the DigestCmd"
9
9
  setup do
10
- Dassets.reset
11
- Dassets.init
10
+ Dassets.config.file_store = 'public'
11
+ clear_store_path(Dassets.config.file_store.root)
12
12
  Dassets.digest_source_files
13
13
 
14
14
  @addfile = 'addfile.txt'
15
- @rmfile = 'file1.txt'
16
- @updfile = 'file2.txt'
17
- @addfile_path = File.join(File.join(Dassets.config.source_path, @addfile))
18
- @rmfile_path = File.join(File.join(Dassets.config.source_path, @rmfile))
19
- @updfile_path = File.join(File.join(Dassets.config.source_path, @updfile))
20
-
21
- @rmfilecontents = File.read(@rmfile_path)
22
- @updfilecontents = File.read(@updfile_path)
23
- @orig_updfile_md5 = Dassets.digests[@updfile]
24
-
25
- FileUtils.touch @addfile_path
26
- FileUtils.rm @rmfile_path
27
- File.open(@updfile_path, "w+"){ |f| f.write('an update') }
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
28
26
  end
29
27
  teardown do
30
- File.open(@updfile_path, "w"){ |f| f.write @updfilecontents }
31
- File.open(@rmfile_path, "w"){ |f| f.write @rmfilecontents }
32
- FileUtils.rm @addfile_path
28
+ File.open(@rmfile_src, "w"){ |f| f.write @rmfile_contents }
29
+ FileUtils.rm @addfile_src
33
30
 
34
- Dassets.reset
35
- Dassets.init
36
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
37
35
  end
38
36
 
39
37
  should "update the digests on all source files when run with no given paths" do
40
- # check before state
41
- assert_equal 5, Dassets.digests.paths.size
42
- assert_not_includes @addfile, Dassets.digests.paths
43
- assert_includes @rmfile, Dassets.digests.paths
44
- assert_equal @orig_updfile_md5, Dassets.digests[@updfile]
45
-
38
+ clear_store_path(Dassets.config.file_store.root)
46
39
  Dassets.digest_source_files
47
40
 
48
- # see the add, update and removal
49
- assert_equal 5, Dassets.digests.paths.size
50
- assert_includes @addfile, Dassets.digests.paths
51
- assert_not_includes @rmfile, Dassets.digests.paths
52
- assert_not_equal @orig_updfile_md5, Dassets.digests[@updfile]
41
+ assert_file_exists @addfile_out
42
+ assert_not_file_exists @rmfile_out
53
43
  end
54
44
 
55
45
  should "update the digests on a single source file when given its path" do
56
- assert_equal 5, Dassets.digests.paths.size
57
- assert_not_includes @addfile, Dassets.digests.paths
46
+ clear_store_path(Dassets.config.file_store.root)
47
+ Dassets.digest_source_files([@addfile_src])
58
48
 
59
- Dassets.digest_source_files([@addfile_path])
49
+ assert_file_exists @addfile_out
50
+ end
51
+
52
+ private
53
+
54
+ def source_path(file)
55
+ File.join(File.join(Dassets.config.source_path, file))
56
+ end
57
+
58
+ def store_path(file)
59
+ Dassets.config.file_store.store_path(Dassets::AssetFile.new(file).url)
60
+ end
60
61
 
61
- # see the add, don't change anything else
62
- assert_equal 6, Dassets.digests.paths.size
63
- assert_includes @addfile, Dassets.digests.paths
64
- assert_includes @rmfile, Dassets.digests.paths
65
- assert_equal @orig_updfile_md5, Dassets.digests[@updfile]
62
+ def clear_store_path(path)
63
+ Dir.glob(File.join(path, '*')).each{ |p| FileUtils.rm_r(p) } if path
66
64
  end
67
65
 
68
66
  end
@@ -10,12 +10,8 @@ module Dassets
10
10
 
11
11
  desc "the middleware in a rack app"
12
12
  setup do
13
- Dassets.init
14
13
  app.use Dassets::Server
15
14
  end
16
- teardown do
17
- Dassets.reset
18
- end
19
15
 
20
16
  def app
21
17
  @app ||= SinatraApp
@@ -29,13 +25,13 @@ module Dassets
29
25
  should "return a successful response" do
30
26
  resp = get '/file1-daa05c683a4913b268653f7a7e36a5b4.txt'
31
27
  assert_equal 200, resp.status
32
- assert_equal Dassets['/file1.txt'].content, resp.body
28
+ assert_equal Dassets['file1.txt'].content, resp.body
33
29
  end
34
30
 
35
31
  should "return a successful response with no body on HEAD requests" do
36
32
  resp = head '/file2-9bbe1047cffbb590f59e0e5aeff46ae4.txt'
37
33
  assert_equal 200, resp.status
38
- assert_equal Dassets['/file2.txt'].size.to_s, resp.headers['Content-Length']
34
+ assert_equal Dassets['file2.txt'].size.to_s, resp.headers['Content-Length']
39
35
  assert_empty resp.body
40
36
  end
41
37
 
@@ -45,7 +41,7 @@ module Dassets
45
41
  desc "requesting an existing asset file that has not been modified"
46
42
  setup do
47
43
  @resp = get('/file1-daa05c683a4913b268653f7a7e36a5b4.txt', {}, {
48
- 'HTTP_IF_MODIFIED_SINCE' => Dassets['/file1.txt'].mtime.to_s
44
+ 'HTTP_IF_MODIFIED_SINCE' => Dassets['file1.txt'].mtime.to_s
49
45
  })
50
46
  end
51
47
 
@@ -1,4 +1,7 @@
1
1
  require 'assert'
2
+ require 'fileutils'
3
+ require 'dassets/file_store'
4
+ require 'dassets/source_cache'
2
5
  require 'dassets/asset_file'
3
6
 
4
7
  class Dassets::AssetFile
@@ -6,69 +9,98 @@ class Dassets::AssetFile
6
9
  class BaseTests < Assert::Context
7
10
  desc "Dassets::AssetFile"
8
11
  setup do
9
- @asset_file = Dassets::AssetFile.new('file1.txt', 'abc123')
12
+ @asset_file = Dassets::AssetFile.new('file1.txt')
10
13
  end
11
14
  subject{ @asset_file }
12
15
 
13
- should have_cmeths :from_abs_path
14
- should have_readers :path, :md5, :dirname, :extname, :basename
15
- should have_readers :output_path, :url, :href
16
- should have_imeth :content, :mtime, :size, :mime_type, :exists?, :==
16
+ should have_readers :digest_path, :dirname, :extname, :basename, :source_cache
17
+ should have_imeths :digest!, :url, :fingerprint, :content
18
+ should have_imeths :href, :mtime, :size, :mime_type, :exists?, :==
17
19
 
18
- should "know its given path and md5" do
19
- assert_equal 'file1.txt', subject.path
20
- assert_equal 'abc123', subject.md5
21
- end
22
-
23
- should "know its dirname, extname, and basename" do
20
+ should "know its digest path, dirname, extname, and basename" do
21
+ assert_equal 'file1.txt', subject.digest_path
24
22
  assert_equal '.', subject.dirname
25
23
  assert_equal '.txt', subject.extname
26
24
  assert_equal 'file1', subject.basename
27
25
  end
28
26
 
29
- should "build it's output_path from the path" do
30
- assert_equal "#{Dassets.config.output_path}/file1.txt", subject.output_path
27
+ should "use its source file attrs as its own" do
28
+ assert_equal subject.source_cache.mtime, subject.mtime
29
+ assert_equal Rack::Utils.bytesize(subject.content), subject.size
30
+ assert_equal "text/plain", subject.mime_type
31
+ assert subject.exists?
32
+
33
+ null_file = Dassets::AssetFile.new('')
34
+ assert_nil null_file.mtime
35
+ assert_nil null_file.size
36
+ assert_nil null_file.mime_type
37
+ assert_not null_file.exists?
38
+ end
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
44
+ end
45
+
46
+ should "have a fingerprint" do
47
+ assert_not_nil subject.fingerprint
48
+ end
49
+
50
+ should "get its fingerprint from its source cache if none is given" do
51
+ af = Dassets::AssetFile.new('file1.txt')
52
+ assert_equal af.source_cache.fingerprint, af.fingerprint
53
+ end
54
+
55
+ should "know it's content" do
56
+ assert_equal "file1.txt\n", subject.content
57
+
58
+ null_file = Dassets::AssetFile.new('')
59
+ assert_nil null_file.content
60
+ end
61
+
62
+ should "get its content from its source cache if no output file" do
63
+ digest_path = 'nested/a-thing.txt.no-use'
64
+ exp_content = "thing\n\nDUMB\nUSELESS"
31
65
 
32
- nested = Dassets::AssetFile.new('nested/file1.txt', 'abc123')
33
- assert_equal "#{Dassets.config.output_path}/nested/file1.txt", nested.output_path
66
+ without_output = Dassets::AssetFile.new(digest_path)
67
+ assert_equal exp_content, without_output.content
34
68
  end
35
69
 
36
- should "build it's url from the path and the md5" do
37
- assert_equal "file1-abc123.txt", subject.url
70
+ should "build it's url from the path and the fingerprint" do
71
+ assert_match /^file1-[a-f0-9]{32}\.txt$/, subject.url
38
72
 
39
- nested = Dassets::AssetFile.new('nested/file1.txt', 'abc123')
40
- assert_equal "nested/file1-abc123.txt", nested.url
73
+ nested = Dassets::AssetFile.new('nested/file1.txt')
74
+ assert_equal "nested/file1-.txt", nested.url
41
75
  end
42
76
 
43
77
  should "build it's href from the url" do
44
- assert_equal "/file1-abc123.txt", subject.href
78
+ assert_match /^\/file1-[a-f0-9]{32}\.txt$/, subject.href
45
79
 
46
- nested = Dassets::AssetFile.new('nested/file1.txt', 'abc123')
47
- assert_equal "/nested/file1-abc123.txt", nested.href
80
+ nested = Dassets::AssetFile.new('nested/file1.txt')
81
+ assert_equal "/nested/file1-.txt", nested.href
48
82
  end
49
83
 
50
- should "be created from absolute file paths and have md5 computed" do
51
- abs_file_path = File.join(Dassets.config.output_path, 'file1.txt')
52
- exp_md5 = 'daa05c683a4913b268653f7a7e36a5b4'
53
- file = Dassets::AssetFile.from_abs_path(abs_file_path)
84
+ end
54
85
 
55
- assert_equal 'file1.txt', file.path
56
- assert_equal exp_md5, file.md5
86
+ class DigestTests < BaseTests
87
+ desc "being digested with an output path configured"
88
+ setup do
89
+ Dassets.config.file_store = 'public'
90
+ @save_path = @asset_file.digest!
91
+ @outfile = Dassets.config.file_store.store_path(@asset_file.url)
92
+ end
93
+ teardown do
94
+ Dassets.config.file_store = Dassets::NullFileStore.new
57
95
  end
58
96
 
59
- should "know it's content, mtime, size, mime_type, and if it exists" do
60
- assert_equal "file1.txt\n", subject.content
61
- assert_equal File.mtime(subject.output_path).httpdate, subject.mtime
62
- assert_equal File.size?(subject.output_path), subject.size
63
- assert_equal "text/plain", subject.mime_type
64
- assert subject.exists?
97
+ should "return the asset file url" do
98
+ assert_equal @outfile, @save_path
99
+ end
65
100
 
66
- null_file = Dassets::AssetFile.new('', '')
67
- assert_nil null_file.content
68
- assert_nil null_file.mtime
69
- assert_nil null_file.size
70
- assert_nil null_file.mime_type
71
- assert_not null_file.exists?
101
+ should "compile and write an asset file to the output path" do
102
+ assert_file_exists @outfile
103
+ assert_equal subject.content, File.read(@outfile)
72
104
  end
73
105
 
74
106
  end
@@ -12,9 +12,10 @@ class Dassets::Config
12
12
  end
13
13
  subject{ @config }
14
14
 
15
- should have_option :root_path, Pathname, :required => true
15
+ should have_option :root_path, Pathname, :required => true
16
16
  should have_option :assets_file, Pathname, :default => ENV['DASSETS_ASSETS_FILE']
17
- should have_options :source_path, :output_path, :digests_path
17
+ should have_options :source_path, :source_filter, :file_store
18
+
18
19
  should have_reader :engines
19
20
  should have_imeth :source, :engine
20
21
 
@@ -23,16 +24,6 @@ class Dassets::Config
23
24
  assert_equal exp_path, subject.source_path
24
25
  end
25
26
 
26
- should "should use `apps/assets/public` as the default output path" do
27
- exp_path = Dassets.config.root_path.join("app/assets/public").to_s
28
- assert_equal exp_path, subject.output_path
29
- end
30
-
31
- should "should use `app/assets/.digests` as the default digests file path" do
32
- exp_path = Dassets.config.root_path.join("app/assets/.digests").to_s
33
- assert_equal exp_path, subject.digests_path.to_s
34
- end
35
-
36
27
  should "set the source path and filter proc with the `sources` method" do
37
28
  path = Dassets::RootPath.new 'app/asset_files'
38
29
  filter = proc{ |paths| [] }
@@ -63,11 +54,6 @@ class Dassets::Config
63
54
  assert_equal '', subject.engines['empty'].compile('some content')
64
55
  end
65
56
 
66
- should "should use `apps/assets/public` as the default files path" do
67
- exp_path = Dassets.config.root_path.join("app/assets/public").to_s
68
- assert_equal exp_path, subject.output_path
69
- end
70
-
71
57
  end
72
58
 
73
59
  end
@@ -8,50 +8,27 @@ module Dassets
8
8
  desc "Dassets"
9
9
  subject{ Dassets }
10
10
 
11
- should have_imeths :config, :sources, :digests
12
- should have_imeths :configure, :reset, :init, :[]
11
+ should have_imeths :config, :configure, :init, :[]
13
12
  should have_imeths :digest_source_files
14
13
 
15
14
  should "return a `Config` instance with the `config` method" do
16
15
  assert_kind_of Config, subject.config
17
16
  end
18
17
 
19
- should "read the source list on init" do
20
- subject.reset
21
- assert_empty subject.sources
22
-
23
- subject.init
24
- assert_not_empty subject.sources
25
- end
26
-
27
- should "read/parse the digests on init" do
28
- subject.reset
29
- assert_empty subject.digests.paths
30
-
31
- subject.init
32
- assert_not_empty subject.digests.paths
33
- end
34
-
35
- should "return asset files given a their path using the index operator" do
36
- subject.init
18
+ should "return asset files given a their digest path using the index operator" do
37
19
  file = subject['nested/file3.txt']
38
20
 
39
21
  assert_kind_of Dassets::AssetFile, file
40
- assert_equal 'nested/file3.txt', file.path
41
- assert_equal 'd41d8cd98f00b204e9800998ecf8427e', file.md5
42
-
43
- subject.reset
22
+ assert_equal 'nested/file3.txt', file.digest_path
23
+ assert_equal 'd41d8cd98f00b204e9800998ecf8427e', file.fingerprint
44
24
  end
45
25
 
46
- should "return an asset file with no fingerprint if path not in digests" do
47
- file = subject['path/not/found.txt']
48
- assert_equal '', file.md5
49
-
50
- subject.init
26
+ should "return an asset file with unknown source if digest path not found" do
51
27
  file = subject['path/not/found.txt']
52
- assert_equal '', file.md5
53
28
 
54
- subject.reset
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?
55
32
  end
56
33
 
57
34
  end
@@ -69,17 +46,6 @@ module Dassets
69
46
  assert_equal exp_list, Dassets::SourceList.new(config)
70
47
  end
71
48
 
72
- should "filter out any paths in the output path" do
73
- config = Dassets::Config.new
74
- config.source_path = "source_files" # test/support/source_files
75
- config.output_path = "source_files/nested"
76
- exp_list = [
77
- 'test1.txt', '_ignored.txt'
78
- ].map{ |p| File.expand_path(p, config.source_path) }.sort
79
-
80
- assert_equal exp_list, Dassets::SourceList.new(config)
81
- end
82
-
83
49
  should "run the supplied source filter on the paths" do
84
50
  config = Dassets::Config.new
85
51
  config.source_path = "source_files" # test/support/source_files