dm-parse 0.2.0 → 0.2.1

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