dm-parse 0.2.0 → 0.2.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.
data/Gemfile CHANGED
@@ -19,3 +19,4 @@ gem "dm-core", ">= 1.2"
19
19
  gem "dm-validations", ">= 1.2"
20
20
  gem "activesupport", ">= 3.2"
21
21
  gem "nestful", ">= 0.0.8"
22
+ gem "mime-types", ">= 1.19"
data/Gemfile.lock CHANGED
@@ -26,6 +26,7 @@ GEM
26
26
  rake
27
27
  rdoc
28
28
  json (1.7.3)
29
+ mime-types (1.19)
29
30
  multi_json (1.3.6)
30
31
  nestful (0.0.8)
31
32
  activesupport (>= 3.0.0.beta)
@@ -56,6 +57,7 @@ DEPENDENCIES
56
57
  dm-core (>= 1.2)
57
58
  dm-validations (>= 1.2)
58
59
  jeweler (>= 1.8.3)
60
+ mime-types (>= 1.19)
59
61
  nestful (>= 0.0.8)
60
62
  rdoc (>= 3.12)
61
63
  rspec (>= 2.10.0)
data/README.md CHANGED
@@ -76,7 +76,7 @@ By this, you can use `User.authenticate(username, password)` to sign in, and use
76
76
  * ParseKey: the property for objectId, `is :parse` will define it for you.
77
77
  * ParsePointer: the pointer, you just need to give it objectId value.
78
78
  * ParseDate: the date, use it like you use DateTime.
79
- * ParseFile: the file, just give it file url.
79
+ * ParseFile: the file, give it a hash contain "name" and "url", or a IO object from web form, it will be uploaded.
80
80
 
81
81
  ## Contributing to dm-parse
82
82
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.2.1
data/dm-parse.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "dm-parse"
8
- s.version = "0.2.0"
8
+ s.version = "0.2.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Zhi-Qiang Lei"]
12
- s.date = "2012-06-28"
12
+ s.date = "2012-06-29"
13
13
  s.description = "An extension to make DataMapper working on Parse.com"
14
14
  s.email = "zhiqiang.lei@gmail.com"
15
15
  s.extra_rdoc_files = [
@@ -64,6 +64,7 @@ Gem::Specification.new do |s|
64
64
  s.add_runtime_dependency(%q<dm-validations>, [">= 1.2"])
65
65
  s.add_runtime_dependency(%q<activesupport>, [">= 3.2"])
66
66
  s.add_runtime_dependency(%q<nestful>, [">= 0.0.8"])
67
+ s.add_runtime_dependency(%q<mime-types>, [">= 1.19"])
67
68
  s.add_development_dependency(%q<rspec>, [">= 2.10.0"])
68
69
  s.add_development_dependency(%q<yard>, [">= 0.7"])
69
70
  s.add_development_dependency(%q<rdoc>, [">= 3.12"])
@@ -76,6 +77,7 @@ Gem::Specification.new do |s|
76
77
  s.add_dependency(%q<dm-validations>, [">= 1.2"])
77
78
  s.add_dependency(%q<activesupport>, [">= 3.2"])
78
79
  s.add_dependency(%q<nestful>, [">= 0.0.8"])
80
+ s.add_dependency(%q<mime-types>, [">= 1.19"])
79
81
  s.add_dependency(%q<rspec>, [">= 2.10.0"])
80
82
  s.add_dependency(%q<yard>, [">= 0.7"])
81
83
  s.add_dependency(%q<rdoc>, [">= 3.12"])
@@ -89,6 +91,7 @@ Gem::Specification.new do |s|
89
91
  s.add_dependency(%q<dm-validations>, [">= 1.2"])
90
92
  s.add_dependency(%q<activesupport>, [">= 3.2"])
91
93
  s.add_dependency(%q<nestful>, [">= 0.0.8"])
94
+ s.add_dependency(%q<mime-types>, [">= 1.19"])
92
95
  s.add_dependency(%q<rspec>, [">= 2.10.0"])
93
96
  s.add_dependency(%q<yard>, [">= 0.7"])
94
97
  s.add_dependency(%q<rdoc>, [">= 3.12"])
@@ -11,7 +11,7 @@ module DataMapper
11
11
  API_KEY_HEADER = "X-Parse-REST-API-Key"
12
12
  MASTER_KEY_HEADER = "X-Parse-Master-Key"
13
13
 
14
- attr_reader :classes, :users, :login, :password_reset
14
+ attr_reader :classes, :users, :login, :password_reset, :file_storage
15
15
 
16
16
  def initialize(name, options)
17
17
  super
@@ -19,6 +19,7 @@ module DataMapper
19
19
  @users = build_parse_resource_for "users"
20
20
  @login = build_parse_resource_for "login"
21
21
  @password_reset = build_parse_resource_for "requestPasswordReset"
22
+ @file_storage = build_parse_resource_for "files"
22
23
  end
23
24
 
24
25
  def parse_resources_for(model)
@@ -93,6 +94,26 @@ module DataMapper
93
94
  password_reset.post params: {email: email}
94
95
  end
95
96
 
97
+ # Upload a file
98
+ # Parse-only
99
+ #
100
+ # @param [String] filename
101
+ # the filename
102
+ #
103
+ # @param [String] content
104
+ # the content
105
+ #
106
+ # @param [String] content_type
107
+ # the content type
108
+ #
109
+ # @return [Hash]
110
+ # the uploaded file information
111
+ def upload_file(filename, content, content_type = MIME::Types.type_for(filename).first)
112
+ headers = file_storage.options[:headers]
113
+ headers = headers.merge("Content-Type" => content_type) if content_type
114
+ file_storage[URI.escape(filename)].post body: content, headers: headers
115
+ end
116
+
96
117
  def delete(resources)
97
118
  resources.each do |resource|
98
119
  parse_resource_for(resource).delete
@@ -108,9 +129,15 @@ module DataMapper
108
129
 
109
130
  private
110
131
  def build_parse_resource_for(name)
132
+ Parse::Resource.new(HOST, format: :json, headers: key_headers)[VERSION][name]
133
+ end
134
+
135
+ def key_headers
111
136
  key_type = @options[:master] ? MASTER_KEY_HEADER : API_KEY_HEADER
112
- headers = {APP_ID_HEADER => @options[:app_id], key_type => @options[:api_key]}
113
- Parse::Resource.new(HOST, format: :json, headers: headers)[VERSION][name]
137
+ {
138
+ APP_ID_HEADER => @options[:app_id],
139
+ key_type => @options[:api_key]
140
+ }
114
141
  end
115
142
 
116
143
  def parse_params_for(query)
data/lib/dm-parse.rb CHANGED
@@ -2,6 +2,7 @@ require "dm-core"
2
2
  require "dm-validations"
3
3
  require "active_support/all"
4
4
  require "nestful"
5
+ require "mime/types"
5
6
  require "collection"
6
7
  require "property/parse_key"
7
8
  require "property/parse_pointer"
@@ -4,11 +4,20 @@ module DataMapper
4
4
  class ParseFile < Object
5
5
 
6
6
  def dump(value)
7
- value && {"__type" => "File", "name" => value.to_s}
7
+ if value.is_a?(Hash)
8
+ value.merge("__type" => "File")
9
+ elsif value.respond_to?(:original_filename) && value.respond_to?(:read)
10
+ adapter = model.repository.adapter
11
+ filename = value.original_filename
12
+ content = value.read
13
+ adapter.upload_file(filename, content).merge("__type" => "File")
14
+ else
15
+ nil
16
+ end
8
17
  end
9
18
 
10
19
  def load(value)
11
- value && value["name"].to_s
20
+ value
12
21
  end
13
22
 
14
23
  end
@@ -96,3 +96,19 @@ describe User do
96
96
  end
97
97
  end
98
98
  end
99
+
100
+ describe "adapter" do
101
+ subject { adapter }
102
+
103
+ let(:adapter) { DataMapper::Repository.adapters[:default] }
104
+
105
+ describe "#upload_file" do
106
+ subject { adapter.upload_file filename, content }
107
+
108
+ let(:filename) { "xf x.txt" }
109
+ let(:content) { "xx" }
110
+
111
+ it { should be_has_key("name") }
112
+ it { should be_has_key("url") }
113
+ end
114
+ end
@@ -221,6 +221,12 @@ describe DataMapper::Adapters::ParseAdapter do
221
221
  it_should_behave_like DataMapper::Parse::Resource
222
222
  end
223
223
 
224
+ describe "#file_storage" do
225
+ subject { adapter.file_storage }
226
+ its(:url) { should eq("https://api.parse.com/1/files") }
227
+ it_should_behave_like DataMapper::Parse::Resource
228
+ end
229
+
224
230
  describe "#parse_resources_for" do
225
231
  subject { adapter.parse_resources_for model }
226
232
  it { should eq(adapter.classes[model.storage_name]) }
@@ -8,23 +8,34 @@ describe DataMapper::Property::ParseFile do
8
8
  describe "#dump" do
9
9
  subject { property.dump value }
10
10
 
11
- let(:value) { "http://a.cn/a.png" }
11
+ let(:value) { { "name" => "xx.txt", "url" => "http://a.cn/xx.txt" } }
12
12
 
13
- it { should eq("__type" => "File", "name" => value) }
13
+ it { should eq(value.merge("__type" => "File")) }
14
14
 
15
15
  context "when value is nil" do
16
16
  let(:value) { nil }
17
17
 
18
18
  it { should be_nil }
19
19
  end
20
+
21
+ context "when value is io" do
22
+ let(:value) { StringIO.new "xx" }
23
+
24
+ before { value.stub(original_filename: "xx.txt") }
25
+ before { DataMapper::Parse::Resource.any_instance.stub(post: {"name" => "x", "url" => "y"}) }
26
+
27
+ it { should be_has_key("__type") }
28
+ it { should be_has_key("name") }
29
+ it { should be_has_key("url") }
30
+ end
20
31
  end
21
32
 
22
33
  describe "#load" do
23
34
  subject { property.load value }
24
35
 
25
- let(:value) { { "__type" => "File", "name" => "http://a.cn/a.png" } }
36
+ let(:value) { { "__type" => "File", "name" => "a.png", "url" => "http://a.cn/a.png" } }
26
37
 
27
- it { should eq(value["name"]) }
38
+ it { should eq(value) }
28
39
 
29
40
  context "when value is nil" do
30
41
  let(:value) { nil }
@@ -36,7 +47,7 @@ describe DataMapper::Property::ParseFile do
36
47
  describe "#valid?" do
37
48
  subject { property.valid? value }
38
49
 
39
- let(:value) { "http://a.cn/a.png" }
50
+ let(:value) { { "__type" => "File", "name" => "a.png", "url" => "http://a.cn/a.png" } }
40
51
 
41
52
  it { should be_true }
42
53
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dm-parse
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-28 00:00:00.000000000 Z
12
+ date: 2012-06-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: dm-core
@@ -75,6 +75,22 @@ dependencies:
75
75
  - - ! '>='
76
76
  - !ruby/object:Gem::Version
77
77
  version: 0.0.8
78
+ - !ruby/object:Gem::Dependency
79
+ name: mime-types
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '1.19'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '1.19'
78
94
  - !ruby/object:Gem::Dependency
79
95
  name: rspec
80
96
  requirement: !ruby/object:Gem::Requirement
@@ -242,7 +258,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
242
258
  version: '0'
243
259
  segments:
244
260
  - 0
245
- hash: -458598293042877060
261
+ hash: 1921482253732220163
246
262
  required_rubygems_version: !ruby/object:Gem::Requirement
247
263
  none: false
248
264
  requirements: