dassets 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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