sixarm_ruby_blob 1.0.0 → 1.0.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a2fbb759d31bb2f54e52e52edd9db4a43f833ebc
4
- data.tar.gz: 3e6d068636b9f1dc652ef6284e7295e31600809e
3
+ metadata.gz: b2498c0f1bc1c1f18d4608c27b90469e5b68218c
4
+ data.tar.gz: 2db4616404f8bd1df0fa333a7dbfd2342549fd23
5
5
  SHA512:
6
- metadata.gz: cf0a87ce08854d34b0e9ff3fa6e43c9d4f9d54d8ec5f0204f56b525e8dc8c680b3b7f3e310b2db84dc24724e2804f064831d2bff2c3e4047de8ffb7a787e52d2
7
- data.tar.gz: e086df08b5fbbe61526a802d04447fb6cfaf3a19d2c32c1133b7bb5d8361e09fc7a01ac2b5eb7e5160d4a7269d9b1f700e54b3311414f16fec155cd2e3d57937
6
+ metadata.gz: 33161d97849da4819f3b996362ec2de113c3f7a60d6a1521d43470aa821c5435a5f69b6abbe261da07e91257b123097ff753d0aa86a16b888c7e426a4f3f5ad3
7
+ data.tar.gz: 9dc6a2e226a9eb1a3d0f738cf8d95d0fb882ffb31f9a360be4d55aeadb4422a95973b30e7fc72cc14e5a7076e49560805fd90ee167b8ab52284e2d246782b8aa
checksums.yaml.gz.sig CHANGED
@@ -1,2 +1 @@
1
-
2
- b@���^��&Y{=��56�<������)�Pl�T�D�8?\�FW�I�ۑd�^ޓ1� ��H$4E���� �.�$Ws+B�"�:"��ި�[�E%�[VG%�yPF~�Ɵ����=Կ��䬎9�#S
1
+ -� ��*X/T�ބ��;�Ӟ#U'3���
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.0
1
+ 1.0.1
@@ -0,0 +1,31 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ ###
4
+ #
5
+ # Blob abstract model suitable for our
6
+ # typical kinds of data files in our app.
7
+ #
8
+ # We can store the blob on the local file system (see BlobFile),
9
+ # We can make the blob accessible via URI (see BlobURI).
10
+ # We can export the blob to an external system (see BlobExport).
11
+ #
12
+ ###
13
+
14
+ class Blob
15
+
16
+ def name; @name; end
17
+ def name=x; @name=x; end
18
+
19
+ def initialize(options = {})
20
+ @name ||= options[:name]
21
+ end
22
+
23
+ def ==(other)
24
+ self.name == other.name
25
+ end
26
+
27
+ def eql?(other)
28
+ self.name.eql?(other.name)
29
+ end
30
+
31
+ end
@@ -0,0 +1,28 @@
1
+ # Blob methods for accessing a blob via a dir name and base name.
2
+ # Exclusively for the Blob class.
3
+
4
+ class Blob
5
+
6
+ #attr_accessor :dir # Dir name of this blob, e.g. "/my/photos"
7
+ #attr_accessor :base # Base name of this blob, e.g. "photo.jpg"
8
+
9
+ def dir; @dir; end
10
+ def dir=(x); @dir=x; end
11
+
12
+ def base; @base; end
13
+ def base=(x); @base=x; end
14
+
15
+ def initialize(options = {})
16
+ @dir ||= options[:dir]
17
+ @base ||= options[:base]
18
+ end
19
+
20
+ def name
21
+ @name ||= "#{dir}/#{base}"
22
+ end
23
+
24
+ def ext
25
+ base =~ /\.(\w+)$/ ? $1 : nil
26
+ end
27
+
28
+ end
@@ -0,0 +1,50 @@
1
+ # Blob methods for exporting.
2
+ # Exclusively for the Blob class.
3
+
4
+ class Blob
5
+
6
+ # Get the blob export's directory name, e.g. "/my/photos"
7
+ #
8
+ # The implementation simply calls #file_dir.
9
+ # Override this when an export needs a custom directory base.
10
+ #
11
+ # @return [String] the blob export's directory name
12
+ #
13
+ def export_dir
14
+ file_dir
15
+ end
16
+
17
+ # Get the blob export's base name, e.g. "photo.jpg"
18
+ #
19
+ # The implementation simply calls #file_base.
20
+ # Override this when an export needs a custom base name.
21
+ #
22
+ # @return [String] the blob export's base name
23
+ #
24
+ def export_base
25
+ file_base
26
+ end
27
+
28
+ # Get the blob export's path, e.g. "/my/photos/photo.jpg"
29
+ #
30
+ # The implementation simply calls #file_path.
31
+ # Override this when an export needs a custom path.
32
+ #
33
+ # @return [String] the blob export's path
34
+ #
35
+ def export_path
36
+ export_pathname.to_s
37
+ end
38
+
39
+ # Get the blob export's pathname, e.g. Pathname("/my/photos/photo.jpg")
40
+ #
41
+ # The implementation simply calls #file_pathname.
42
+ # Override this when an export needs a custom path.
43
+ #
44
+ # @return [String] the file's path suitable for export
45
+ #
46
+ def export_pathname
47
+ Pathname(export_dir) + export_base
48
+ end
49
+
50
+ end
@@ -0,0 +1,73 @@
1
+ # Blob file methods for accessing a blob via the filesystem.
2
+ # Exclusively for the Blob class.
3
+
4
+ class Blob
5
+
6
+ # Get the blob file's dir name e.g. "/my/photos".
7
+ #
8
+ # This impl calls #dir which is typically fine.
9
+ #
10
+ # Override this if the local storage file dir
11
+ # name is different than the generic base name.
12
+ #
13
+ # @return [String] the blob file's dir name
14
+ #
15
+ def file_dir
16
+ dir
17
+ end
18
+
19
+ # Get the blob file's base name e.g. "photo.jpg".
20
+ #
21
+ # This impl calls #base which is typically fine.
22
+ #
23
+ # Override this when the local storage file base
24
+ # name is different than the generic base name.
25
+ #
26
+ # @return [String] the blob file's base name
27
+ #
28
+ def file_base
29
+ base
30
+ end
31
+
32
+ # Get the blob file's path e.g. "/my/photos/photo.jpg"
33
+ #
34
+ # This impl calls #file_dir and #file_base.
35
+ # Subclasses can likely use this as-is.
36
+ #
37
+ # @return [Pathname] the blob file's path
38
+ #
39
+ def file_path
40
+ file_pathname.to_s
41
+ end
42
+
43
+ # Get the blob file's pathname e.g. Pathname("/my/photos/photo.jpg")
44
+ #
45
+ # This impl calls #file_dir and #file_base.
46
+ # Subclasses can likely use this as-is.
47
+ #
48
+ # @return [Pathname] the blob file's pathname
49
+ #
50
+ def file_pathname
51
+ Pathname(file_dir) + file_base
52
+ end
53
+
54
+ # Does the file exist on the local filesystem?
55
+ #
56
+ # @return [boolean] iff the file exists
57
+ #
58
+ def file_exist?
59
+ FileTest.exists? file_path
60
+ end
61
+
62
+ # Return true iff the image exists the way we expect.
63
+ # Currently, this is simply calling file_exist.
64
+ #
65
+ # @deprecated
66
+ # @return [boolean] iff the file exists
67
+ #
68
+ def exist?
69
+ Rails.logger.warn "DEPRECATED"
70
+ FileTest.exists? file_path
71
+ end
72
+
73
+ end
@@ -0,0 +1,51 @@
1
+ # Blob method to upload from a web page.
2
+ # Exclusively for the Blob class.
3
+
4
+ class Blob
5
+
6
+ # Upload to this blob's file_path from a web form file_field.
7
+ #
8
+ # TODO optimize this to move the temp file into place
9
+ #
10
+ # @return [Boolean] true iff the upload succeeds
11
+ #
12
+ def upload(file_field)
13
+ self.class.upload(file_path, file_field)
14
+ end
15
+
16
+ # Upload to a file_path from a web form file_field.
17
+ #
18
+ # TODO optimize this to move the temp file into place
19
+ #
20
+ # @return [Boolean] true iff the upload succeeds
21
+ #
22
+ def self.upload(file_path, file_field)
23
+ if vet_file_field?(file_field)
24
+ file_field.tempfile.binmode
25
+ File.open(file_path, "wb") { |f| f.write(file_field.read) }
26
+ return true
27
+ end
28
+ return false
29
+ end
30
+
31
+ # Vet the file field for all the methods that we expect
32
+ # from a web browser upload; we call this before we upload.
33
+ #
34
+ def self.vet_file_field?(file_field)
35
+ !!(
36
+ file_field \
37
+ && file_field.respond_to?(:tempfile) \
38
+ && file_field.tempfile \
39
+ && file_field.tempfile.respond_to?(:path) \
40
+ && file_field.tempfile.respond_to?(:binmode) \
41
+ && file_field.tempfile.path
42
+ )
43
+ end
44
+
45
+ # Deprecated
46
+ #
47
+ def save(file_field)
48
+ raise "Deprecated: replace with #upload"
49
+ end
50
+
51
+ end
@@ -0,0 +1,64 @@
1
+ # Blob URI methods for accessing a blob via the web.
2
+ # Exclusively for the Blob class.
3
+
4
+ class Blob
5
+
6
+ # Get the blob URI's dir name e.g. "/my/photos".
7
+ #
8
+ # This impl calls #dir which is typically fine.
9
+ #
10
+ # Override this if the local storage file dir
11
+ # name is different than the generic base name.
12
+ #
13
+ # @return [String] the blob URI's dir name
14
+ #
15
+ def uri_dir
16
+ dir
17
+ end
18
+
19
+ # Get the blob's URI base name e.g. "photo.jpg".
20
+ #
21
+ # This impl calls #base which is typically fine.
22
+ #
23
+ # Override this when the URI base name
24
+ # is different than the generic base name.
25
+ #
26
+ # @return [String] the blob URI's base name
27
+ #
28
+ def uri_base
29
+ base
30
+ end
31
+
32
+ # Get the blob's URI to access this blob from the web.
33
+ #
34
+ # This impl calls #uri_dir and #uri_base.
35
+ # Override this e.g. for assets, CDNs, etc.
36
+ #
37
+ # @return [String] the blob URI's path
38
+ #
39
+ def uri
40
+ return "/#{uri_dir}/#{uri_base}"
41
+ end
42
+
43
+ # Get the blob's URI to access this blob from the web,
44
+ # with a random chaff query appended as a cache buster.
45
+ #
46
+ # @return [String] the blob URI's path?uuid=chaff
47
+ #
48
+ def uri_cacheless
49
+ return "#{uri}?cacheless=#{SecureRandom.uuid}"
50
+ end
51
+
52
+ # Deprecated
53
+ #
54
+ def url
55
+ raise "Deprecated: replace with #uri"
56
+ end
57
+
58
+ # Deprecated
59
+ #
60
+ def url_cacheless
61
+ raise "Deprecated: replace with #uri_cacheless"
62
+ end
63
+
64
+ end
@@ -0,0 +1,56 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'minitest/autorun'
3
+ require 'simplecov'
4
+ SimpleCov.start
5
+
6
+ describe Blob do
7
+
8
+ let(:blob){ Factory.build(:blob, name: FAB.name) }
9
+
10
+ describe "equality" do
11
+
12
+ before do
13
+ @a = Blob.new
14
+ @b = Blob.new
15
+ end
16
+
17
+ describe "#==(other)" do
18
+
19
+ it "is true iff names are equal (using ==)" do
20
+ @a.name = "foo"
21
+ @b.name = "foo"
22
+ (@a==@b).must_be_true
23
+ end
24
+
25
+ it "is false when names are inequal (using ==)" do
26
+ @a.name = "foo"
27
+ @b.name = "bar"
28
+ (@a==@b).must_be_false
29
+ end
30
+
31
+ end
32
+
33
+ describe "#eql?(other)" do
34
+
35
+ before do
36
+ @a = Blob.new
37
+ @b = Blob.new
38
+ end
39
+
40
+ it "is true iff names are equal (using #eql?)" do
41
+ @a.name = "foo"
42
+ @b.name = "foo"
43
+ (@a.eql?(@b)).must_be_true
44
+ end
45
+
46
+ it "is false when names are inequal (using #eql?)" do
47
+ @a.name = "foo"
48
+ @b.name = "bar"
49
+ (@a.eql?(@b)).must_be_false
50
+ end
51
+
52
+ end
53
+
54
+ end
55
+
56
+ end
@@ -0,0 +1,52 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'minitest/autorun'
3
+ require 'simplecov'
4
+ SimpleCov.start
5
+
6
+ describe Blob do
7
+
8
+ let(:dir){ FAB.dirname }
9
+ let(:base){ FAB.basename }
10
+ let(:blob){ Blob.new(dir: dir, base: base) }
11
+
12
+ # We choose to use Unix-friendly file names: lowercase a-z and underscores,
13
+ # always with "/" as a directory separator, typically with a dot extension,
14
+ # never with non-ASCII characters.
15
+ #
16
+ let(:base_match){ /^[0-1a-z\_\.]+$/ }
17
+ let(:dir_match){ /^[0-1a-z\_\/]+$/ }
18
+ let(:path_match){ /^[0-1a-z\_\/\.]+$/ }
19
+
20
+ describe "#base" do
21
+ it "uses a good unix name" do
22
+ blob.base.must_match base_match
23
+ end
24
+ end
25
+
26
+ describe "#dir" do
27
+ it "uses a good unix name" do
28
+ blob.dir.must_match dir_match
29
+ end
30
+ end
31
+
32
+ describe "#name" do
33
+ it "concats the name" do
34
+ blob.name.must_equal "#{dir}/#{base}"
35
+ end
36
+ end
37
+
38
+ describe "#ext" do
39
+
40
+ it "returns the file base name extension, if it exists" do
41
+ blob.base = "foo.goo.hoo"
42
+ blob.ext.must_equal "hoo"
43
+ end
44
+
45
+ it "returns nil, if there is no extension" do
46
+ blob.base = "foogoohoo"
47
+ blob.ext.must_be_nil
48
+ end
49
+
50
+ end
51
+
52
+ end
@@ -0,0 +1,38 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'minitest/autorun'
3
+ require 'simplecov'
4
+ SimpleCov.start
5
+
6
+ describe Blob do
7
+
8
+ let(:dir){ "abc" }
9
+ let(:base){ "def" }
10
+ let(:blob){ Blob.new(dir: dir, base: base) }
11
+
12
+ describe "#export_dir" do
13
+
14
+ it "defaults to the file dir" do
15
+ blob.export_dir.must_equal blob.file_dir
16
+ blob.export_dir.must_equal "#{dir}"
17
+ end
18
+
19
+ end
20
+
21
+ describe "#export_base" do
22
+
23
+ it "it defaults to the file base" do
24
+ blob.export_base.must_equal blob.file_base
25
+ blob.export_base.must_match "#{base}"
26
+ end
27
+
28
+ end
29
+
30
+ describe "#export_path" do
31
+
32
+ it "combines the dir and base" do
33
+ blob.export_path.must_equal "#{dir}/#{base}"
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,64 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'minitest/autorun'
3
+ require 'simplecov'
4
+ SimpleCov.start
5
+
6
+ describe Blob do
7
+
8
+ let(:dir){ "abc" }
9
+ let(:base){ "def" }
10
+ let(:blob){ Blob.new(dir: dir, base: base) }
11
+
12
+ # We choose to use Unix-friendly file names: lowercase a-z and underscores,
13
+ # always with "/" as a directory separator, typically with a dot extension,
14
+ # never with non-ASCII characters.
15
+ #
16
+ let(:base_match){ /^[0-1a-z\_\.]+$/ }
17
+ let(:dir_match){ /^[0-1a-z\_\/]+$/ }
18
+ let(:path_match){ /^[0-1a-z\_\/\.]+$/ }
19
+
20
+ describe "#file_dir" do
21
+
22
+ it "is the dir" do
23
+ blob.file_dir.must_equal dir
24
+ end
25
+
26
+ it "uses a good unix name" do
27
+ blob.file_dir.must_match dir_match
28
+ end
29
+
30
+ end
31
+
32
+ describe "#file_base" do
33
+
34
+ it "is the base" do
35
+ blob.file_base.must_equal base
36
+ end
37
+
38
+ it "uses a good unix name" do
39
+ blob.file_base.must_match base_match
40
+ end
41
+
42
+ end
43
+
44
+ describe "#file_path" do
45
+
46
+ it "combines the dir and base" do
47
+ blob.file_path.must_equal "#{dir}/#{base}"
48
+ end
49
+
50
+ it "uses a good unix name" do
51
+ blob.file_path.must_match path_match
52
+ end
53
+
54
+ end
55
+
56
+ describe "#file_exist?" do
57
+
58
+ it "returns true iff the file exists" do
59
+ blob.file_exist? #TODO
60
+ end
61
+
62
+ end
63
+
64
+ end
@@ -0,0 +1,74 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'minitest/autorun'
3
+ require 'simplecov'
4
+ SimpleCov.start
5
+
6
+ describe Blob do
7
+
8
+ DIR = Pathname(__FILE__).dirname + "samples"
9
+ BASE = "upload_output.bin"
10
+ TEMPFILE_PATH = DIR + "upload_input.bin"
11
+ TEMPFILE_BINMODE = true
12
+
13
+ let(:blob){ Blob.new(dir: DIR, base: BASE) }
14
+ let(:original_filename){ "hello" }
15
+ let(:content_type){ "abc/def" }
16
+
17
+ # Mocks
18
+ let(:tempfile){ OpenStruct.new(path: TEMPFILE_PATH, binmode: TEMPFILE_BINMODE) }
19
+ let(:file_field){ OpenStruct.new(content_type: content_type, original_filename: original_filename, tempfile: tempfile) }
20
+
21
+ describe "upload" do
22
+
23
+ before do
24
+ @file_path = blob.file_path
25
+
26
+ # Delete a previously-uploaded file if it exists
27
+ File.exists?(@file_path) and File.delete(@file_path)
28
+
29
+ # Sanity check
30
+ File.exists?(tempfile.path).must_be_true "Temp file must exist: #{tempfile.path}"
31
+
32
+ end
33
+
34
+ describe ".upload" do
35
+
36
+ it "uploads" do
37
+ File.exists?(@file_path).must_be_false "Blob file must not exist: #{@file_path}"
38
+ blob.upload(file_field).must_be_true
39
+ File.exists?(@file_path).must_be_true "Blob file must exist: #{@file_path}"
40
+ end
41
+
42
+ end
43
+
44
+ describe "#upload" do
45
+
46
+ it "uploads" do
47
+ File.exists?(@file_path).must_be_false "Blob file must not exist: #{@file_path}"
48
+ Blob.upload(@file_path, file_field).must_be_true
49
+ File.exists?(@file_path).must_be_true "Blob file must exist: #{@file_path}"
50
+ end
51
+
52
+ end
53
+
54
+ describe "#vet_file_field" do
55
+
56
+ before do
57
+ # Sanity check
58
+ file_field.must_exist
59
+ file_field.must_respond_to :tempfile
60
+ file_field.tempfile.must_be_exist
61
+ file_field.tempfile.must_respond_to :path
62
+ file_field.tempfile.must_respond_to :binmode
63
+ file_field.tempfile.path.must_exist
64
+ end
65
+
66
+ it "vets" do
67
+ Blob.vet_file_field?(file_field).must_be_true
68
+ end
69
+
70
+ end
71
+
72
+ end
73
+
74
+ end
@@ -0,0 +1,54 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'minitest/autorun'
3
+ require 'simplecov'
4
+ SimpleCov.start
5
+
6
+ describe Blob do
7
+
8
+ let(:dir){ "foo" }
9
+ let(:base){ "bar" }
10
+ let(:blob){ Blob.new(dir: dir, base: base) }
11
+
12
+ describe "#uri_dir" do
13
+
14
+ it "is the dir" do
15
+ blob.uri_dir.must_equal dir
16
+ end
17
+
18
+ end
19
+
20
+ describe "#uri_base" do
21
+
22
+ it "is the base" do
23
+ blob.uri_base.must_equal base
24
+ end
25
+
26
+ end
27
+
28
+ describe "#uri" do
29
+
30
+ it "returns a URI that we can parse successfully" do
31
+ URI.parse(blob.uri)
32
+ end
33
+
34
+ end
35
+
36
+ describe "#uri_cacheless" do
37
+
38
+ it "gets a URI that we can parse successfully" do
39
+ URI.parse(blob.uri_cacheless)
40
+ end
41
+
42
+ it "gets a URI that has a unique id appended" do
43
+ blob.uri_cacheless.must_match /\?cacheless=[-0-9abcdef]{36}$/
44
+ end
45
+
46
+ it "returns a URI that is different each time" do
47
+ x = blob.uri_cacheless
48
+ y = blob.uri_cacheless
49
+ x.wont_equal y
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -10,8 +10,6 @@ require 'sixarm_ruby_blob'
10
10
  require 'securerandom'
11
11
  require 'uri'
12
12
 
13
-
14
-
15
13
  FAB = Fab.new
16
14
 
17
15
  ['base','dir','file','export','upload','uri'].map{|x|
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sixarm_ruby_blob
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - SixArm
@@ -70,7 +70,20 @@ files:
70
70
  - README.md
71
71
  - VERSION
72
72
  - lib/sixarm_ruby_blob.rb
73
+ - lib/sixarm_ruby_blob/base.rb
74
+ - lib/sixarm_ruby_blob/dir.rb
75
+ - lib/sixarm_ruby_blob/file.rb
76
+ - lib/sixarm_ruby_blob/export.rb
77
+ - lib/sixarm_ruby_blob/upload.rb
78
+ - lib/sixarm_ruby_blob/uri.rb
73
79
  - test/sixarm_ruby_blob_test.rb
80
+ - test/sixarm_ruby_blob_test/base_test.rb
81
+ - test/sixarm_ruby_blob_test/dir_test.rb
82
+ - test/sixarm_ruby_blob_test/file_test.rb
83
+ - test/sixarm_ruby_blob_test/export_test.rb
84
+ - test/sixarm_ruby_blob_test/upload_test.rb
85
+ - test/sixarm_ruby_blob_test/uri_test.rb
86
+ - test/sixarm_ruby_blob_test/samples/upload_input.bin
74
87
  homepage: http://sixarm.com/
75
88
  licenses:
76
89
  - BSD
@@ -101,4 +114,11 @@ specification_version: 4
101
114
  summary: SixArm.com » Ruby » Blob of data abstract base class
102
115
  test_files:
103
116
  - test/sixarm_ruby_blob_test.rb
117
+ - test/sixarm_ruby_blob_test/base_test.rb
118
+ - test/sixarm_ruby_blob_test/dir_test.rb
119
+ - test/sixarm_ruby_blob_test/file_test.rb
120
+ - test/sixarm_ruby_blob_test/export_test.rb
121
+ - test/sixarm_ruby_blob_test/upload_test.rb
122
+ - test/sixarm_ruby_blob_test/uri_test.rb
123
+ - test/sixarm_ruby_blob_test/samples/upload_input.bin
104
124
  has_rdoc: true
metadata.gz.sig CHANGED
Binary file