motional 0.1.0

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.
@@ -0,0 +1,32 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ module MotionAL
4
+ #
5
+ # A wrapper of ALAssetLibrary class.
6
+ #
7
+ # An instance of ALAssetsLibrary provides access to the videos and photos that are under the control of the Photos application.
8
+ # The library includes those that are in the Saved Photos album, those coming from iTunes, and those that were directly imported into the device. You use it to retrieve the list of all asset groups and to save images and videos into the Saved Photos album.
9
+ #
10
+ # And added some convinience methods.
11
+ #
12
+ class Library
13
+ # @return [Class] An alias of MotionAL::Group class
14
+ attr_reader :groups
15
+
16
+ # @return [MotionAL::Library] Singleton instance.
17
+ def self.instance
18
+ Dispatch.once { @@instance ||= new }
19
+ @@instance
20
+ end
21
+
22
+ def initialize
23
+ @groups = MotionAL::Group
24
+ end
25
+
26
+ # An instance of ALAssetLibrary.
27
+ # @return [ALAssetsLibrary]
28
+ def al_asset_library
29
+ @al_asset_library ||= ALAssetsLibrary.new
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,101 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ module MotionAL
4
+ #
5
+ # A wrapper of ALRepresentation class.
6
+ #
7
+ # An ALAssetRepresentation object encapsulates one of the representations of a given ALAsset object.
8
+ # A given asset in the library may have more than one representation. For example, if a camera provides RAW and JPEG versions of an image, the resulting asset will have two representations—one for the RAW file and one for the JPEG file.
9
+ #
10
+ # And added some convinience methods.
11
+ #
12
+ class Representation
13
+ attr_reader :asset, :al_asset_representation
14
+
15
+ # @param asset [MotionAL::Asset] A parent asset.
16
+ # @param al_asset_representation [ALAssetRepresentation] An instance of ALAssetRepresentation.
17
+ def initialize(asset, al_asset_representation)
18
+ @asset = asset
19
+ @al_asset_representation = al_asset_representation
20
+ end
21
+
22
+ # return a NSConcreteData(kind of NSData) object for the representation file.
23
+ #
24
+ # support only jpeg and png.
25
+ #
26
+ # @return [NSConcreteData]
27
+ def data
28
+ ui_image = UIImage.imageWithCGImage(self.cg_image)
29
+ if self.filename =~ /.jpe?g$/i
30
+ NSData.alloc.initWithData(UIImageJPEGRepresentation(ui_image, 0.0))
31
+ elsif self.filename =~ /.png$/i
32
+ NSData.alloc.initWithData(UIImagePNGRepresentation(ui_image))
33
+ else
34
+ nil
35
+ end
36
+ end
37
+
38
+ # @param options [Hash] described for CGImageSourceCreateWithData or CGImageSourceCreateWithURL.
39
+ # @return [CGImageRef] A full resolution CGImage of the representation.
40
+ def cg_image_with_options(options)
41
+ @al_asset_representation.CGImageWithOptions(options)
42
+ end
43
+
44
+ # The orientation of the representation.
45
+ #
46
+ # @return [Symbol] :up, :down :left, :right, :up_mirrored, :down_mirrored, :left_mirrored or :right_mirrored
47
+ #
48
+ # @see MotionAL.asset_orientations
49
+ def orientation
50
+ MotionAL.asset_orientations.key(@al_asset.valueForProperty(ALAssetPropertyOrientation))
51
+ end
52
+
53
+ # A CGImage of the representation.
54
+ #
55
+ # @return [CGImageRef]
56
+ # @return [nil] When the representation has no CGImage.
57
+ def full_resolution_image
58
+ @al_asset_representation.fullResolutionImage
59
+ end
60
+ alias_method :cg_image, :full_resolution_image
61
+
62
+ # A CGImage of the representation that is appropriate for displaying full screen.
63
+ #
64
+ # @return [CGImageRef]
65
+ # @return [nil] When the representation has no CGImage.
66
+ def full_screen_image
67
+ @al_asset_representation.fullScreenImage
68
+ end
69
+
70
+ # Metadata of the representation.
71
+ #
72
+ # @return [Hash] A multidimensional hash.
73
+ # @return [nil] When the representation has no metadata or incompatible metadata.
74
+ def metadata
75
+ @al_asset_representation.metadata
76
+ end
77
+
78
+ class << self
79
+ private
80
+ # wrapper for method
81
+ # @!macro [attach] make_wrapper
82
+ # The representation's $1
83
+ #
84
+ # @method $1
85
+ # @return [$2]
86
+ def make_wrapper_for_method(method_name, type_of_return)
87
+ define_method(method_name) do
88
+ @al_asset_representation.send(method_name)
89
+ end
90
+ end
91
+ end
92
+
93
+ make_wrapper_for_method(:scale, "Float")
94
+ make_wrapper_for_method(:dimensions, "CGSize")
95
+ make_wrapper_for_method(:filename, "String")
96
+ make_wrapper_for_method(:size, "Fixnum")
97
+ make_wrapper_for_method(:url, "NSURL")
98
+ make_wrapper_for_method(:UTI, "String")
99
+ alias_method :name, :filename
100
+ end
101
+ end
@@ -0,0 +1,55 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ module MotionAL
4
+ #
5
+ # A collection of representations.
6
+ # Representations belongs to the asset.
7
+ #
8
+ class Representations
9
+ # @param asset [MotionAL::Asset]
10
+ def initialize(asset)
11
+ @asset = asset
12
+ end
13
+
14
+ # Find a representation by a specified representation UTI.
15
+ #
16
+ # @param representation_uti [String] A representation's UTI
17
+ # @return [nil]
18
+ #
19
+ # @yield [representation]
20
+ # @yieldparam representation [MotionAL::Representation] A found representation.
21
+ #
22
+ # @example
23
+ # asset.representations.find_by_uti(representation_uti) do |rep|
24
+ # p rep.filename
25
+ # end
26
+ def find_by_uti(representation_uti, &block)
27
+ al_rep = @asset.al_asset.representationForUTI(representation_uti)
28
+ if al_rep
29
+ block.call(Representation.new(@asset, al_rep))
30
+ else
31
+ nil # not found
32
+ end
33
+ end
34
+
35
+ # Find and enumerate representations of the asset.
36
+ #
37
+ # @return [nil]
38
+ #
39
+ # @yield [representation]
40
+ # @yieldparam representation [MotionAL::Representation] A found representation.
41
+ #
42
+ # @example
43
+ # asset.representations.find_all do |rep|
44
+ # p rep.filename
45
+ # end
46
+ def find_all(&block)
47
+ @asset.representation_utis.each do |uti|
48
+ find_by_uti(uti) do |rep|
49
+ block.call(rep)
50
+ end
51
+ end
52
+ end
53
+ alias_method :each, :find_all
54
+ end
55
+ end
@@ -0,0 +1,3 @@
1
+ class MotionAL
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'motional/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "motional"
8
+ spec.version = MotionAL::VERSION
9
+ spec.authors = ["akahigeg"]
10
+ spec.email = ["akahigeg@gmail.com"]
11
+ spec.description = %q{AssetLibrary framework wrapper for RubyMotion}
12
+ spec.summary = %q{AssetLibrary framework wrapper for RubyMotion}
13
+ spec.homepage = "https://github.com/akahigeg/motional"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "motion-redgreen"
24
+ end
Binary file
Binary file
@@ -0,0 +1,274 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ describe MotionAL::Asset do
4
+ before do
5
+ @library = MotionAL.library
6
+
7
+ MotionAL::Asset.find_all do |asset, error|
8
+ @existent_asset = asset if asset.asset_type == :photo && @existent_asset.nil?
9
+ @existent_video_asset = asset if asset.asset_type == :video && @existent_video_asset.nil?
10
+ end
11
+ wait_async(0.5)
12
+
13
+ @video_url = NSBundle.mainBundle.URLForResource('sample', withExtension:"mp4")
14
+
15
+ MotionAL::Group.find_all do |group, error|
16
+ @test_group = group if group.name == TEST_GROUP_NAME
17
+ end
18
+ wait_async
19
+
20
+ MotionAL::Group.find_camera_roll do |group, error|
21
+ @saved_photos = group
22
+ end
23
+ wait_async
24
+ end
25
+
26
+ shared "asset creation" do
27
+ it "should create new asset" do
28
+ @calling_create_method.should.change do
29
+ wait_async(0.5)
30
+ @saved_photos.assets.count(:all)
31
+ end
32
+ end
33
+ end
34
+
35
+ describe ".create" do
36
+ describe "when pass a CGImage with metadata" do
37
+ before do
38
+ @calling_create_method = Proc.new do
39
+ MotionAL::Asset.create(@existent_asset.full_resolution_image, @existent_asset.metadata)
40
+ end
41
+ end
42
+
43
+ behaves_like "asset creation"
44
+ end
45
+
46
+ describe "when pass a CGImage with orientation" do
47
+ before do
48
+ @calling_create_method = Proc.new do
49
+ MotionAL::Asset.create(@existent_asset.full_resolution_image, orientation: :up)
50
+ end
51
+ end
52
+
53
+ behaves_like "asset creation"
54
+ end
55
+
56
+ describe "when pass a NSData" do
57
+ before do
58
+ @calling_create_method = Proc.new do
59
+ MotionAL::Asset.create(@existent_asset.data, @existent_asset.metadata)
60
+ end
61
+ end
62
+
63
+ behaves_like "asset creation"
64
+ end
65
+
66
+ describe "when pass a video path" do
67
+ before do
68
+ @calling_create_method = Proc.new do
69
+ MotionAL::Asset.create(@video_url)
70
+ end
71
+ end
72
+
73
+ behaves_like "asset creation"
74
+ end
75
+ end
76
+
77
+ describe "#save_new" do
78
+ describe "when pass a NSData" do
79
+ before do
80
+ @calling_create_method = Proc.new do
81
+ @new_asset = nil
82
+ @existent_asset.save_new(@existent_asset.data, @existent_asset.metadata) {|a| @new_asset = a }
83
+ wait_async(0.5)
84
+ end
85
+ end
86
+
87
+ behaves_like "asset creation"
88
+
89
+ it "new asset have the 'original_asset'" do
90
+ @new_asset.original_asset.filename.should == @existent_asset.filename
91
+ end
92
+ end
93
+
94
+ describe "when pass a video path" do
95
+ before do
96
+ @calling_create_method = Proc.new do
97
+ @new_asset = @existent_video_asset.save_new(@video_url)
98
+ end
99
+ end
100
+
101
+ behaves_like "asset creation"
102
+ end
103
+ end
104
+
105
+ describe "#update" do
106
+ describe "when pass a NSData" do
107
+ before do
108
+ @calling_update_method = Proc.new do
109
+ @existent_asset.update(@existent_asset.data, @existent_asset.metadata)
110
+ end
111
+ end
112
+
113
+ it "should not create new asset" do
114
+ @calling_update_method.should.not.change do
115
+ @saved_photos.assets.count(:all)
116
+ end
117
+ end
118
+ end
119
+
120
+ describe "when pass a video path" do
121
+ before do
122
+ @calling_update_method = Proc.new do
123
+ @existent_video_asset.update(@video_url)
124
+ end
125
+ end
126
+
127
+ it "should not create new asset" do
128
+ @calling_update_method.should.not.change do
129
+ @saved_photos.assets.count(:all)
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ describe "#find_by_url" do
136
+ it "should find the Asset" do
137
+ asset = nil
138
+ MotionAL::Asset.find_by_url(@existent_asset.url) do |asset|
139
+ asset = asset
140
+ end
141
+ wait_async
142
+
143
+ asset.should.instance_of MotionAL::Asset
144
+ end
145
+
146
+ it "should return nil when unknown url given" do
147
+ url = NSURL.URLWithString("http://hogehoge")
148
+ asset = nil
149
+ MotionAL::Asset.find_by_url(url) {|a| asset = a }
150
+ wait_async
151
+
152
+ asset.should.be.nil
153
+ end
154
+
155
+ it "should accept url string" do
156
+ asset = nil
157
+ MotionAL::Asset.find_by_url(@existent_asset.url.absoluteString) do |asset|
158
+ asset = asset
159
+ end
160
+ wait_async
161
+
162
+ asset.url.should.equal @existent_asset.url
163
+ end
164
+ end
165
+
166
+ describe "#all" do
167
+ it "should avail order asc" do
168
+ assets = []
169
+
170
+ MotionAL::Asset.find_all(order: :asc) {|a| assets << a }
171
+ wait_async
172
+
173
+ assets.size.should > 1
174
+ assets.first.url.should.equal @existent_asset.url
175
+ end
176
+
177
+ it "should avail order desc" do
178
+ assets = []
179
+
180
+ MotionAL::Asset.find_all(order: :desc) {|a| assets << a }
181
+ wait_async
182
+
183
+ assets.size.should > 1
184
+ assets.last.url.should.equal @existent_asset.url
185
+ end
186
+
187
+ it "should avail group option" do
188
+ assets_a = []
189
+ assets_b = []
190
+
191
+ MotionAL::Asset.find_all {|a| assets_a << a }
192
+ MotionAL::Asset.find_all(group: @test_group) {|a| assets_b << a }
193
+ wait_async
194
+
195
+ assets_a.size.should.equal @saved_photos.assets.count(:all)
196
+ assets_a.size.should.not.equal assets_b.size
197
+ end
198
+
199
+ it "should avail indexset option" do
200
+ indexset = NSMutableIndexSet.indexSetWithIndexesInRange(1..2)
201
+ assets = []
202
+
203
+ MotionAL::Asset.find_all(indexset: indexset) {|a| assets << a }
204
+ wait_async
205
+
206
+ assets.size.should.equal 2
207
+
208
+ # @saved_photos.assets[1].url.should.equal assets.first.url
209
+ end
210
+
211
+ it "should avail indexset option with order option" do
212
+ indexset = NSMutableIndexSet.indexSetWithIndexesInRange(1..3)
213
+ assets = []
214
+
215
+ MotionAL::Asset.find_all(indexset: indexset, order: :desc) {|a| assets << a }
216
+ wait_async
217
+
218
+ assets.size.should.equal 3
219
+
220
+ # @saved_photos.assets[1..3].reverse.first.url.should.equal assets.first.url
221
+ end
222
+
223
+ it "should avail filter option" do
224
+ assets = []
225
+ photos = []
226
+
227
+ MotionAL::Asset.find_all(filter: :all) {|a| assets << a }
228
+ MotionAL::Asset.find_all(filter: :photo) {|a| photos << a }
229
+ wait_async
230
+
231
+ assets.size.should.not.equal photos.size
232
+ end
233
+ # TODO: limit and offset option
234
+ end
235
+
236
+ describe "#editable?" do
237
+ it "asset is created by this App should be editable" do
238
+ @existent_asset.should.be.editable
239
+ end
240
+ end
241
+
242
+ describe "#representation" do
243
+ it "should be default representation" do
244
+ @existent_asset.representation.should == @existent_asset.default_representation
245
+ end
246
+ end
247
+
248
+ describe "#representations" do
249
+ it "should instance of Representations" do
250
+ @existent_asset.representations.should.instance_of MotionAL::Representations
251
+ end
252
+
253
+ it "should have Representation instance" do
254
+ @existent_asset.representations.find_all do |rep|
255
+ @rep = rep
256
+ end
257
+ @rep.should.instance_of MotionAL::Representation
258
+ end
259
+ end
260
+
261
+ describe "#asset_type" do
262
+ it "should be human readable" do
263
+ @existent_asset.asset_type.should.equal :photo
264
+ end
265
+ end
266
+
267
+ describe "#orientation" do
268
+ it "should be human readable" do
269
+ @existent_asset.orientation.should.equal :up
270
+ end
271
+ end
272
+
273
+ # TODO: what's happen when treat raw file
274
+ end