joint 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,5 +1,5 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- gem 'i18n'
3
+ gem 'i18n', '0.4.2'
4
4
  gem 'bson_ext', '~> 1.1', :require => false
5
5
  gemspec
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- joint (0.5)
4
+ joint (0.5.1)
5
5
  mime-types
6
6
  mongo_mapper (~> 0.8.6)
7
7
  wand (~> 0.3)
@@ -37,7 +37,7 @@ PLATFORMS
37
37
 
38
38
  DEPENDENCIES
39
39
  bson_ext (~> 1.1)
40
- i18n
40
+ i18n (= 0.4.2)
41
41
  jnunemaker-matchy
42
42
  joint!
43
43
  mime-types
@@ -3,150 +3,38 @@ require 'mime/types'
3
3
  require 'wand'
4
4
 
5
5
  module Joint
6
- autoload :Version, 'joint/version'
7
-
8
6
  def self.configure(model)
9
7
  model.class_inheritable_accessor :attachment_names
10
8
  model.attachment_names = Set.new
11
9
  model.send(:include, model.attachment_accessor_module)
12
10
  end
13
11
 
14
- module ClassMethods
15
- def attachment_accessor_module
16
- @attachment_accessor_module ||= Module.new
17
- end
18
-
19
- def attachment(name, options = {})
20
- options.symbolize_keys!
21
- name = name.to_sym
22
-
23
- self.attachment_names << name
24
-
25
- after_save :save_attachments
26
- after_save :destroy_nil_attachments
27
- before_destroy :destroy_all_attachments
28
-
29
- key :"#{name}_id", ObjectId
30
- key :"#{name}_name", String
31
- key :"#{name}_size", Integer
32
- key :"#{name}_type", String
33
-
34
- validates_presence_of(name) if options[:required]
35
-
36
- attachment_accessor_module.module_eval <<-EOC
37
- def #{name}
38
- @#{name} ||= AttachmentProxy.new(self, :#{name})
39
- end
40
-
41
- def #{name}?
42
- !nil_attachments.include?(:#{name}) && send(:#{name}_id?)
43
- end
44
-
45
- def #{name}=(file)
46
- if file.nil?
47
- nil_attachments << :#{name}
48
- assigned_attachments.delete(:#{name})
49
- else
50
- send("#{name}_id=", BSON::ObjectId.new) if send("#{name}_id").nil?
51
- send("#{name}_size=", File.size(file))
52
- send("#{name}_type=", Wand.wave(file.path, :original_filename => Joint.file_name(file)))
53
- send("#{name}_name=", Joint.file_name(file))
54
- assigned_attachments[:#{name}] = file
55
- nil_attachments.delete(:#{name})
56
- end
57
- end
58
- EOC
12
+ def self.name(file)
13
+ if file.respond_to?(:original_filename)
14
+ file.original_filename
15
+ else
16
+ File.basename(file.path)
59
17
  end
60
18
  end
61
19
 
62
- module InstanceMethods
63
- def grid
64
- @grid ||= Mongo::Grid.new(database)
20
+ def self.size(file)
21
+ if file.respond_to?(:size)
22
+ file.size
23
+ else
24
+ File.size(file)
65
25
  end
66
-
67
- private
68
- def assigned_attachments
69
- @assigned_attachments ||= {}
70
- end
71
-
72
- def nil_attachments
73
- @nil_attachments ||= Set.new
74
- end
75
-
76
- # IO must respond to read and rewind
77
- def save_attachments
78
- assigned_attachments.each_pair do |name, io|
79
- next unless io.respond_to?(:read)
80
- io.rewind if io.respond_to?(:rewind)
81
- grid.delete(send(name).id)
82
- grid.put(io.read, {
83
- :_id => send(name).id,
84
- :filename => send(name).name,
85
- :content_type => send(name).type,
86
- })
87
- end
88
- assigned_attachments.clear
89
- end
90
-
91
- def destroy_nil_attachments
92
- # currently MM does not send sets to instance as well
93
- nil_attachments.each do |name|
94
- grid.delete(send(name).id)
95
- send(:"#{name}_id=", nil)
96
- send(:"#{name}_size=", nil)
97
- send(:"#{name}_type=", nil)
98
- send(:"#{name}_name=", nil)
99
- set({
100
- :"#{name}_id" => nil,
101
- :"#{name}_size" => nil,
102
- :"#{name}_type" => nil,
103
- :"#{name}_name" => nil,
104
- })
105
- end
106
-
107
- nil_attachments.clear
108
- end
109
-
110
- def destroy_all_attachments
111
- self.class.attachment_names.map { |name| grid.delete(send(name).id) }
112
- end
113
26
  end
114
27
 
115
- class AttachmentProxy
116
- def initialize(instance, name)
117
- @instance, @name = instance, name
28
+ def self.type(file)
29
+ if file.respond_to?(:content_type)
30
+ file.content_type
31
+ else
32
+ Wand.wave(file.path, :original_filename => Joint.name(file))
118
33
  end
119
-
120
- def id
121
- @instance.send("#{@name}_id")
122
- end
123
-
124
- def name
125
- @instance.send("#{@name}_name")
126
- end
127
-
128
- def size
129
- @instance.send("#{@name}_size")
130
- end
131
-
132
- def type
133
- @instance.send("#{@name}_type")
134
- end
135
-
136
- def nil?
137
- !@instance.send("#{@name}?")
138
- end
139
-
140
- def grid_io
141
- @grid_io ||= @instance.grid.get(id)
142
- end
143
-
144
- def method_missing(method, *args, &block)
145
- grid_io.send(method, *args, &block)
146
- end
147
- end
148
-
149
- def self.file_name(file)
150
- file.respond_to?(:original_filename) ? file.original_filename : File.basename(file.path)
151
34
  end
152
35
  end
36
+
37
+ require 'joint/class_methods'
38
+ require 'joint/instance_methods'
39
+ require 'joint/attachment_proxy'
40
+ require 'joint/io'
@@ -0,0 +1,35 @@
1
+ module Joint
2
+ class AttachmentProxy
3
+ def initialize(instance, name)
4
+ @instance, @name = instance, name
5
+ end
6
+
7
+ def id
8
+ @instance.send("#{@name}_id")
9
+ end
10
+
11
+ def name
12
+ @instance.send("#{@name}_name")
13
+ end
14
+
15
+ def size
16
+ @instance.send("#{@name}_size")
17
+ end
18
+
19
+ def type
20
+ @instance.send("#{@name}_type")
21
+ end
22
+
23
+ def nil?
24
+ !@instance.send("#{@name}?")
25
+ end
26
+
27
+ def grid_io
28
+ @grid_io ||= @instance.grid.get(id)
29
+ end
30
+
31
+ def method_missing(method, *args, &block)
32
+ grid_io.send(method, *args, &block)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,49 @@
1
+ module Joint
2
+ module ClassMethods
3
+ def attachment_accessor_module
4
+ @attachment_accessor_module ||= Module.new
5
+ end
6
+
7
+ def attachment(name, options = {})
8
+ options.symbolize_keys!
9
+ name = name.to_sym
10
+
11
+ self.attachment_names << name
12
+
13
+ after_save :save_attachments
14
+ after_save :destroy_nil_attachments
15
+ before_destroy :destroy_all_attachments
16
+
17
+ key :"#{name}_id", ObjectId
18
+ key :"#{name}_name", String
19
+ key :"#{name}_size", Integer
20
+ key :"#{name}_type", String
21
+
22
+ validates_presence_of(name) if options[:required]
23
+
24
+ attachment_accessor_module.module_eval <<-EOC
25
+ def #{name}
26
+ @#{name} ||= AttachmentProxy.new(self, :#{name})
27
+ end
28
+
29
+ def #{name}?
30
+ !nil_attachments.include?(:#{name}) && send(:#{name}_id?)
31
+ end
32
+
33
+ def #{name}=(file)
34
+ if file.nil?
35
+ nil_attachments << :#{name}
36
+ assigned_attachments.delete(:#{name})
37
+ else
38
+ send("#{name}_id=", BSON::ObjectId.new) if send("#{name}_id").nil?
39
+ send("#{name}_name=", Joint.name(file))
40
+ send("#{name}_size=", Joint.size(file))
41
+ send("#{name}_type=", Joint.type(file))
42
+ assigned_attachments[:#{name}] = file
43
+ nil_attachments.delete(:#{name})
44
+ end
45
+ end
46
+ EOC
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,54 @@
1
+ module Joint
2
+ module InstanceMethods
3
+ def grid
4
+ @grid ||= Mongo::Grid.new(database)
5
+ end
6
+
7
+ private
8
+ def assigned_attachments
9
+ @assigned_attachments ||= {}
10
+ end
11
+
12
+ def nil_attachments
13
+ @nil_attachments ||= Set.new
14
+ end
15
+
16
+ # IO must respond to read and rewind
17
+ def save_attachments
18
+ assigned_attachments.each_pair do |name, io|
19
+ next unless io.respond_to?(:read)
20
+ io.rewind if io.respond_to?(:rewind)
21
+ grid.delete(send(name).id)
22
+ grid.put(io.read, {
23
+ :_id => send(name).id,
24
+ :filename => send(name).name,
25
+ :content_type => send(name).type,
26
+ })
27
+ end
28
+ assigned_attachments.clear
29
+ end
30
+
31
+ def destroy_nil_attachments
32
+ # currently MM does not send sets to instance as well
33
+ nil_attachments.each do |name|
34
+ grid.delete(send(name).id)
35
+ send(:"#{name}_id=", nil)
36
+ send(:"#{name}_size=", nil)
37
+ send(:"#{name}_type=", nil)
38
+ send(:"#{name}_name=", nil)
39
+ set({
40
+ :"#{name}_id" => nil,
41
+ :"#{name}_size" => nil,
42
+ :"#{name}_type" => nil,
43
+ :"#{name}_name" => nil,
44
+ })
45
+ end
46
+
47
+ nil_attachments.clear
48
+ end
49
+
50
+ def destroy_all_attachments
51
+ self.class.attachment_names.map { |name| grid.delete(send(name).id) }
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,14 @@
1
+ module Joint
2
+ class IO
3
+ attr_accessor :name, :content, :content_type, :size
4
+
5
+ def initialize(attrs={})
6
+ attrs.each { |key, value| send("#{key}=", value) }
7
+ @content_type ||= 'plain/text'
8
+ @size ||= @content.size unless @content.nil?
9
+ end
10
+
11
+ alias path name
12
+ alias read content
13
+ end
14
+ end
@@ -1,3 +1,3 @@
1
1
  module Joint
2
- Version = '0.5.1'
2
+ Version = '0.5.2'
3
3
  end
@@ -1,16 +1,3 @@
1
- def growl(title, msg, img)
2
- %x{growlnotify -m #{ msg.inspect} -t #{title.inspect} --image ~/.watchr/#{img}.png}
3
- end
4
-
5
- def form_growl_message(str)
6
- results = str.split("\n").last
7
- if results =~ /[1-9]\s(failure|error)s?/
8
- growl "Test Results", "#{results}", "fail"
9
- elsif results != ""
10
- growl "Test Results", "#{results}", "pass"
11
- end
12
- end
13
-
14
1
  def run(cmd)
15
2
  puts(cmd)
16
3
  output = ""
@@ -21,7 +8,7 @@ def run(cmd)
21
8
  $stdout.flush
22
9
  end
23
10
  end
24
- form_growl_message output
11
+ output
25
12
  end
26
13
 
27
14
  def run_test_file(file)
@@ -37,7 +24,7 @@ def related_test_files(path)
37
24
  end
38
25
 
39
26
  watch('test/test_helper\.rb') { system('clear'); run_all_tests }
40
- watch('test/test_.*\.rb') { |m| system('clear'); run_test_file(m[0]) }
27
+ watch('test/.*test_.*\.rb') { |m| system('clear'); run_test_file(m[0]) }
41
28
  watch('lib/.*') { |m| related_test_files(m[0]).each { |file| run_test_file(file) } }
42
29
 
43
30
  # Ctrl-\
@@ -37,4 +37,44 @@ class Test::Unit::TestCase
37
37
  def assert_no_grid_difference(&block)
38
38
  assert_grid_difference(0, &block)
39
39
  end
40
+ end
41
+
42
+ class Asset
43
+ include MongoMapper::Document
44
+ plugin Joint
45
+
46
+ key :title, String
47
+ attachment :image
48
+ attachment :file
49
+ end
50
+
51
+ class BaseModel
52
+ include MongoMapper::Document
53
+ plugin Joint
54
+ attachment :file
55
+ end
56
+
57
+ class Image < BaseModel; attachment :image end
58
+ class Video < BaseModel; attachment :video end
59
+
60
+ module JointTestHelpers
61
+ def all_files
62
+ [@file, @image, @image2, @test1, @test2]
63
+ end
64
+
65
+ def rewind_files
66
+ all_files.each { |file| file.rewind }
67
+ end
68
+
69
+ def open_file(name)
70
+ File.open(File.join(File.dirname(__FILE__), 'fixtures', name), 'r')
71
+ end
72
+
73
+ def grid
74
+ @grid ||= Mongo::Grid.new(MongoMapper.database)
75
+ end
76
+
77
+ def key_names
78
+ [:id, :name, :type, :size]
79
+ end
40
80
  end
@@ -0,0 +1,28 @@
1
+ require 'helper'
2
+
3
+ class IOTest < Test::Unit::TestCase
4
+ context "#initialize" do
5
+ should "set attributes from hash" do
6
+ Joint::IO.new(:name => 'foo').name.should == 'foo'
7
+ end
8
+ end
9
+
10
+ should "default content_type to plain text" do
11
+ Joint::IO.new.content_type.should == 'plain/text'
12
+ end
13
+
14
+ should "default size to content size" do
15
+ content = 'This is my content'
16
+ Joint::IO.new(:content => content).size.should == content.size
17
+ end
18
+
19
+ should "alias path to name" do
20
+ Joint::IO.new(:name => 'foo').path.should == 'foo'
21
+ end
22
+
23
+ context "#read" do
24
+ should "return content" do
25
+ Joint::IO.new(:content => 'Testing').read.should == 'Testing'
26
+ end
27
+ end
28
+ end
@@ -1,45 +1,5 @@
1
1
  require 'helper'
2
2
 
3
- class Asset
4
- include MongoMapper::Document
5
- plugin Joint
6
-
7
- key :title, String
8
- attachment :image
9
- attachment :file
10
- end
11
-
12
- class BaseModel
13
- include MongoMapper::Document
14
- plugin Joint
15
- attachment :file
16
- end
17
-
18
- class Image < BaseModel; attachment :image end
19
- class Video < BaseModel; attachment :video end
20
-
21
- module JointTestHelpers
22
- def all_files
23
- [@file, @image, @image2, @test1, @test2]
24
- end
25
-
26
- def rewind_files
27
- all_files.each { |file| file.rewind }
28
- end
29
-
30
- def open_file(name)
31
- File.open(File.join(File.dirname(__FILE__), 'fixtures', name), 'r')
32
- end
33
-
34
- def grid
35
- @grid ||= Mongo::Grid.new(MongoMapper.database)
36
- end
37
-
38
- def key_names
39
- [:id, :name, :type, :size]
40
- end
41
- end
42
-
43
3
  class JointTest < Test::Unit::TestCase
44
4
  include JointTestHelpers
45
5
 
@@ -56,6 +16,45 @@ class JointTest < Test::Unit::TestCase
56
16
  all_files.each { |file| file.close }
57
17
  end
58
18
 
19
+ context ".name" do
20
+ should "return original_filename" do
21
+ def @image.original_filename
22
+ 'frank.jpg'
23
+ end
24
+ Joint.name(@image).should == 'frank.jpg'
25
+ end
26
+
27
+ should "fall back to File.basename" do
28
+ Joint.name(@image).should == 'mr_t.jpg'
29
+ end
30
+ end
31
+
32
+ context ".size" do
33
+ should "return size" do
34
+ def @image.size
35
+ 25
36
+ end
37
+ Joint.size(@image).should == 25
38
+ end
39
+
40
+ should "fall back to File.size" do
41
+ Joint.size(@image).should == 13661
42
+ end
43
+ end
44
+
45
+ context ".type" do
46
+ should "return type" do
47
+ def @image.content_type
48
+ 'plain/text'
49
+ end
50
+ Joint.type(@image).should == 'plain/text'
51
+ end
52
+
53
+ should "fall back to Wand" do
54
+ Joint.type(@image).should == 'image/jpeg'
55
+ end
56
+ end
57
+
59
58
  context "Using Joint plugin" do
60
59
  should "add each attachment to attachment_names" do
61
60
  Asset.attachment_names.should == Set.new([:image, :file])
@@ -343,4 +342,23 @@ class JointTest < Test::Unit::TestCase
343
342
  model.should be_valid
344
343
  end
345
344
  end
345
+
346
+ context "Assigning joint io instance" do
347
+ setup do
348
+ io = Joint::IO.new({
349
+ :name => 'foo.txt',
350
+ :content_type => 'plain/text',
351
+ :content => 'This is my stuff',
352
+ :size => 19,
353
+ })
354
+ @asset = Asset.create(:file => io)
355
+ end
356
+
357
+ should "work" do
358
+ @asset.file_name.should == 'foo.txt'
359
+ @asset.file_size.should == 19
360
+ @asset.file_type.should == 'plain/text'
361
+ @asset.file.read.should == 'This is my stuff'
362
+ end
363
+ end
346
364
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: joint
3
3
  version: !ruby/object:Gem::Version
4
- hash: 9
4
+ hash: 15
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 5
9
- - 1
10
- version: 0.5.1
9
+ - 2
10
+ version: 0.5.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - John Nunemaker
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-12-20 00:00:00 -05:00
18
+ date: 2010-12-30 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -122,6 +122,10 @@ files:
122
122
  - Rakefile
123
123
  - joint.gemspec
124
124
  - lib/joint.rb
125
+ - lib/joint/attachment_proxy.rb
126
+ - lib/joint/class_methods.rb
127
+ - lib/joint/instance_methods.rb
128
+ - lib/joint/io.rb
125
129
  - lib/joint/version.rb
126
130
  - specs.watchr
127
131
  - test/fixtures/harmony.png
@@ -130,6 +134,7 @@ files:
130
134
  - test/fixtures/test2.txt
131
135
  - test/fixtures/unixref.pdf
132
136
  - test/helper.rb
137
+ - test/joint/test_io.rb
133
138
  - test/test_joint.rb
134
139
  has_rdoc: true
135
140
  homepage: http://github.com/jnunemaker/joint
@@ -172,4 +177,5 @@ test_files:
172
177
  - test/fixtures/test2.txt
173
178
  - test/fixtures/unixref.pdf
174
179
  - test/helper.rb
180
+ - test/joint/test_io.rb
175
181
  - test/test_joint.rb