rapinoe 0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a7b0b8295ed07411999367b9d49c5f04afbfc62e
4
+ data.tar.gz: 2086de2bda02ddd0adca922539ba33a51e49c3ea
5
+ SHA512:
6
+ metadata.gz: 5a8b0fad50b816d783c76a50176e6bd9668d12511d49983065d130e8ea475fa8c5a638cab90c7dbf671120c596ba219e3ea08ab130947ca84d879dc6395e3433
7
+ data.tar.gz: e37ae7a82f002d55a31831cb2ebb9a4169c8f78c915894d84a1f7c1fdbd627605ac68bbc82a796221d01f1c488108aa2c61edc004f2b9f1f2b393357bda7bc30
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "http://rubygems.org"
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,19 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rapinoe (0.0.1)
5
+ rubyzip (~> 1.1.7)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ rubyzip (1.1.7)
11
+
12
+ PLATFORMS
13
+ ruby
14
+
15
+ DEPENDENCIES
16
+ rapinoe!
17
+
18
+ BUNDLED WITH
19
+ 1.11.2
data/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) Zach Holman, http://zachholman.com
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ ![megan rapinoe](https://cloud.githubusercontent.com/assets/2723/12370366/16ac568a-bbc3-11e5-951d-f9367476eae2.jpg)
2
+
3
+ # Rapinoe
4
+
5
+ Rapinoe helps you parse Apple Keynote files.
6
+
7
+ Primarily it's designed to help you access the simple metadata of a Keynote file: return how many slides there are, extract the slide previews baked into the file, tell you various details about the file itself on disk, and so on.
8
+
9
+ ## Install
10
+
11
+ ```sh
12
+ gem install rapinoe
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ```ruby
18
+ rapinoe = Rapinoe.new('talks/Literal Best Player Ever.key')
19
+ # => <Rapinoe::Keynote: @name="Literal Best Player Ever", @path="talks/Literal Best Player Ever.key", @data=[…]>
20
+
21
+ rapinoe.write_preview_to_file("my_dope_talk.jpg")
22
+ # => Writes the higher quality 1024px-width preview of your entire deck to a file
23
+
24
+ rapinoe.slides
25
+ # => [<Rapinoe::Slide>, <Rapinoe::Slide>, <Rapinoe::Slide>, <Rapinoe::Slide>]
26
+
27
+ rapinoe.slides.first.write_preview_to_file("/tmp/slide-preview.jpg")
28
+ # => writes the Keynote-generated slide preview to a file
29
+ ```
data/Rakefile ADDED
@@ -0,0 +1,134 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'date'
4
+
5
+ #############################################################################
6
+ #
7
+ # Helper functions
8
+ #
9
+ #############################################################################
10
+
11
+ def name
12
+ @name ||= Dir['*.gemspec'].first.split('.').first
13
+ end
14
+
15
+ def version
16
+ line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
17
+ line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
18
+ end
19
+
20
+ def date
21
+ Date.today.to_s
22
+ end
23
+
24
+ def rubyforge_project
25
+ name
26
+ end
27
+
28
+ def gemspec_file
29
+ "#{name}.gemspec"
30
+ end
31
+
32
+ def gem_file
33
+ "#{name}-#{version}.gem"
34
+ end
35
+
36
+ def replace_header(head, header_name)
37
+ head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
38
+ end
39
+
40
+ #############################################################################
41
+ #
42
+ # Standard tasks
43
+ #
44
+ #############################################################################
45
+
46
+ task :default => :test
47
+
48
+ require 'rake/testtask'
49
+ Rake::TestTask.new(:test) do |test|
50
+ test.libs << 'lib' << 'test' << '.'
51
+ test.pattern = 'test/**/test_*.rb'
52
+ test.verbose = true
53
+ end
54
+
55
+ desc "Open an irb session preloaded with this library"
56
+ task :console do
57
+ sh "irb -rubygems -r ./lib/#{name}.rb"
58
+ end
59
+
60
+ #############################################################################
61
+ #
62
+ # Custom tasks (add your own tasks here)
63
+ #
64
+ #############################################################################
65
+
66
+
67
+
68
+ #############################################################################
69
+ #
70
+ # Packaging tasks
71
+ #
72
+ #############################################################################
73
+
74
+ desc "Create tag v#{version} and build and push #{gem_file} to Rubygems"
75
+ task :release => :build do
76
+ unless `git branch` =~ /^\* master$/
77
+ puts "You must be on the master branch to release!"
78
+ exit!
79
+ end
80
+ sh "git commit --allow-empty -a -m 'Release #{version}'"
81
+ sh "git tag v#{version}"
82
+ sh "git push origin master"
83
+ sh "git push origin v#{version}"
84
+ sh "gem push pkg/#{name}-#{version}.gem"
85
+ end
86
+
87
+ desc "Build #{gem_file} into the pkg directory"
88
+ task :build => :gemspec do
89
+ sh "mkdir -p pkg"
90
+ sh "gem build #{gemspec_file}"
91
+ sh "mv #{gem_file} pkg"
92
+ end
93
+
94
+ desc "Generate #{gemspec_file}"
95
+ task :gemspec => :validate do
96
+ # read spec file and split out manifest section
97
+ spec = File.read(gemspec_file)
98
+ head, manifest, tail = spec.split(" # = MANIFEST =\n")
99
+
100
+ # replace name version and date
101
+ replace_header(head, :name)
102
+ replace_header(head, :version)
103
+ replace_header(head, :date)
104
+ #comment this out if your rubyforge_project has a different name
105
+ replace_header(head, :rubyforge_project)
106
+
107
+ # determine file list from git ls-files
108
+ files = `git ls-files`.
109
+ split("\n").
110
+ sort.
111
+ reject { |file| file =~ /^\./ }.
112
+ reject { |file| file =~ /^(rdoc|pkg)/ }.
113
+ map { |file| " #{file}" }.
114
+ join("\n")
115
+
116
+ # piece file back together and write
117
+ manifest = " s.files = %w[\n#{files}\n ]\n"
118
+ spec = [head, manifest, tail].join(" # = MANIFEST =\n")
119
+ File.open(gemspec_file, 'w') { |io| io.write(spec) }
120
+ puts "Updated #{gemspec_file}"
121
+ end
122
+
123
+ desc "Validate #{gemspec_file}"
124
+ task :validate do
125
+ libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
126
+ unless libfiles.empty?
127
+ puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
128
+ exit!
129
+ end
130
+ unless Dir['VERSION*'].empty?
131
+ puts "A `VERSION` file at root level violates Gem best practices."
132
+ exit!
133
+ end
134
+ end
@@ -0,0 +1,70 @@
1
+ module Rapinoe
2
+ class Keynote
3
+ # The path where we can find the .key file.
4
+ attr_accessor :path
5
+
6
+ # The name of the file.
7
+ attr_accessor :name
8
+
9
+ # The (first stage) of uncompressed Keynote data in memory.
10
+ attr_accessor :data
11
+
12
+ # Create a new Keynote instance.
13
+ #
14
+ # path - The path to the .key file on disk.
15
+ #
16
+ # Returns a Keynote.
17
+ def initialize(path)
18
+ @path = path
19
+ @name = File.basename(path, ".key")
20
+ extract_key_file
21
+ end
22
+
23
+ # Returns the file size of the Keynote file in bytes.
24
+ def size
25
+ File.size(path)
26
+ end
27
+
28
+ def slides
29
+ @data.glob("Data/st*").map do |preview_jpg_data|
30
+ Slide.new(preview_jpg_data.get_input_stream.read)
31
+ end
32
+ end
33
+
34
+ # The binary data associated with the .jpg Keynote writes to make a
35
+ # high(ish) quality preview version of the deck. You likely will want to
36
+ # access this via #write_preview_to_file, unless you have specific needs for
37
+ # the binary data.
38
+ #
39
+ # Returns the contents of preview.jpg.
40
+ def preview_data
41
+ @data.find_entry("preview.jpg").get_input_stream.read
42
+ end
43
+
44
+ # Writes Keynote's preview.jpg to disk somewhere.
45
+ #
46
+ # path - The path to the new file you want to write.
47
+ #
48
+ # Returns nothing.
49
+ def write_preview_to_file(path)
50
+ File.open(path, 'wb') do |out|
51
+ out.write(preview_data)
52
+ end
53
+ end
54
+
55
+ def inspect
56
+ "<Rapinoe::Keynote: @name=\"#{@name}\", @path=\"#{@path}\", @data=[…]>"
57
+ end
58
+
59
+ private
60
+
61
+ # .key files basically just try to masquerade as .zip files. Once we extract
62
+ # the main directory structure (in memory), we can start looking into what's
63
+ # inside.
64
+ #
65
+ # Returns a complex data structure that maps to Zip::File.
66
+ def extract_key_file
67
+ @data = Zip::File.open(path)
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,45 @@
1
+ module Rapinoe
2
+ # `Slide` is a really vague approximation. Keynote stores its data in a
3
+ # zip-compressed file that has a bunch of .iwa files in it, which is where it
4
+ # stores its data. Each of those .iwa files is a file that's been compressed
5
+ # with a non-standard version of Google's Snappy compression format, and in
6
+ # turn the resulting data is stored in Google's Protobuf interchange format.
7
+ #
8
+ # I think we could probably get pretty deep into this, but I couldn't get the
9
+ # Ruby Snappy bindings to decompress the .iwa data (presumably due to the
10
+ # lacking Stream Identifier chunk). Might be something we look into later and
11
+ # see how many details we can glean from the full dataset.
12
+ #
13
+ # For more information, see @obriensp's excellent docs:
14
+ # https://github.com/obriensp/iWorkFileFormat/blob/master/Docs/index.md
15
+ #
16
+ # For now, we're going to instead look at the generated jpeg previews inside
17
+ # the `Data/` subdirectory. It's a nasty approximation, but it should map
18
+ # fairly well to the actual number of slides in the file.
19
+ class Slide
20
+ # The binary data representing the jpeg representation of this slide.
21
+ attr_accessor :data
22
+
23
+ def initialize(data)
24
+ @data = data
25
+ end
26
+
27
+ # The contents of the preview jpeg, loaded into memory.
28
+ #
29
+ # Returns a string of the jpeg's binary data.
30
+ def preview_data
31
+ @data
32
+ end
33
+
34
+ # Writes the preview for this slide to disk.
35
+ def write_preview_to_file(path)
36
+ File.open(path, 'wb') do |out|
37
+ out.write(preview_data)
38
+ end
39
+ end
40
+
41
+ def inspect
42
+ "<Rapinoe::Slide>"
43
+ end
44
+ end
45
+ end
data/lib/rapinoe.rb ADDED
@@ -0,0 +1,12 @@
1
+ require 'zip'
2
+
3
+ require_relative 'rapinoe/keynote'
4
+ require_relative 'rapinoe/slide'
5
+
6
+ module Rapinoe
7
+ VERSION = '0.0.1'
8
+
9
+ def self.new(path)
10
+ Keynote.new(path)
11
+ end
12
+ end
data/rapinoe.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'rapinoe'
3
+ s.version = '0.0.1'
4
+ s.licenses = ['MIT']
5
+ s.summary = "Parse Keynote files in Ruby."
6
+ s.description = "Rapinoe is designed to parse the native files for Apple's Keynote presentation software. Its main focus is to help extract previews and general metadata about the presentation."
7
+ s.authors = ["Zach Holman"]
8
+ s.email = 'zach@zachholman.com'
9
+ s.files = ["lib/rapinoe.rb"]
10
+ s.homepage = 'https://github.com/holman/rapinoe'
11
+ s.require_paths = %w[lib]
12
+ s.add_runtime_dependency 'rubyzip', '~> 1.1', '>= 1.1.7'
13
+
14
+ # = MANIFEST =
15
+ s.files = %w[
16
+ Gemfile
17
+ Gemfile.lock
18
+ LICENSE.md
19
+ README.md
20
+ Rakefile
21
+ lib/rapinoe.rb
22
+ lib/rapinoe/keynote.rb
23
+ lib/rapinoe/slide.rb
24
+ rapinoe.gemspec
25
+ test/fixtures/ice-cream.key
26
+ test/test_keynote.rb
27
+ test/test_rapinoe.rb
28
+ test/test_slide.rb
29
+ ]
30
+ # = MANIFEST =
31
+
32
+ s.test_files = s.files.select { |path| path =~ /^test\/test_.*\.rb/ }
33
+ end
Binary file
@@ -0,0 +1,45 @@
1
+ require 'test/unit'
2
+ require 'lib/rapinoe'
3
+ include Rapinoe
4
+
5
+ class TestKeynote < Test::Unit::TestCase
6
+ def setup
7
+ @keynote = Keynote.new('test/fixtures/ice-cream.key')
8
+ end
9
+
10
+ def test_path
11
+ assert_equal 'test/fixtures/ice-cream.key', @keynote.path
12
+ end
13
+
14
+ def test_name
15
+ assert_equal "ice-cream", @keynote.name
16
+ end
17
+
18
+ def test_size
19
+ assert_equal 327378, @keynote.size
20
+ end
21
+
22
+ def test_slides
23
+ assert_kind_of Rapinoe::Slide, @keynote.slides.first
24
+ end
25
+
26
+ def test_data
27
+ assert_not_nil @keynote.data
28
+ end
29
+
30
+ def test_preview_data
31
+ assert_equal 32858, @keynote.preview_data.size
32
+ end
33
+
34
+ def test_write_preview_to_file
35
+ tempfile = "/tmp/rapinoe-test.jpg"
36
+
37
+ refute File.exist?(tempfile)
38
+ @keynote.write_preview_to_file(tempfile)
39
+
40
+ assert File.exist?(tempfile)
41
+ assert_operator File.size(tempfile), :>, 32858
42
+ ensure
43
+ File.delete tempfile
44
+ end
45
+ end
@@ -0,0 +1,12 @@
1
+ require 'test/unit'
2
+ require 'lib/rapinoe'
3
+
4
+ class TestRapinoe < Test::Unit::TestCase
5
+ def setup
6
+ @keynote = Rapinoe.new('test/fixtures/ice-cream.key')
7
+ end
8
+
9
+ def test_quick_initializes
10
+ assert_kind_of Rapinoe::Keynote, @keynote
11
+ end
12
+ end
@@ -0,0 +1,26 @@
1
+ require 'test/unit'
2
+ require 'lib/rapinoe'
3
+ include Rapinoe
4
+
5
+ class TestSlide < Test::Unit::TestCase
6
+ def setup
7
+ @keynote = Keynote.new('test/fixtures/ice-cream.key')
8
+ @slide = @keynote.slides.first
9
+ end
10
+
11
+ def test_preview_data
12
+ assert_equal 1484, @slide.preview_data.size
13
+ end
14
+
15
+ def test_write_preview_to_file
16
+ tempfile = "/tmp/rapinoe-slide-preview.jpg"
17
+
18
+ refute File.exist?(tempfile)
19
+ @slide.write_preview_to_file(tempfile)
20
+
21
+ assert File.exist?(tempfile)
22
+ assert_operator File.size(tempfile), :>, 1484
23
+ ensure
24
+ File.delete tempfile
25
+ end
26
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rapinoe
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Zach Holman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-01-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rubyzip
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.1.7
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1.1'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.1.7
33
+ description: Rapinoe is designed to parse the native files for Apple's Keynote presentation
34
+ software. Its main focus is to help extract previews and general metadata about
35
+ the presentation.
36
+ email: zach@zachholman.com
37
+ executables: []
38
+ extensions: []
39
+ extra_rdoc_files: []
40
+ files:
41
+ - Gemfile
42
+ - Gemfile.lock
43
+ - LICENSE.md
44
+ - README.md
45
+ - Rakefile
46
+ - lib/rapinoe.rb
47
+ - lib/rapinoe/keynote.rb
48
+ - lib/rapinoe/slide.rb
49
+ - rapinoe.gemspec
50
+ - test/fixtures/ice-cream.key
51
+ - test/test_keynote.rb
52
+ - test/test_rapinoe.rb
53
+ - test/test_slide.rb
54
+ homepage: https://github.com/holman/rapinoe
55
+ licenses:
56
+ - MIT
57
+ metadata: {}
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ requirements: []
73
+ rubyforge_project:
74
+ rubygems_version: 2.5.1
75
+ signing_key:
76
+ specification_version: 4
77
+ summary: Parse Keynote files in Ruby.
78
+ test_files:
79
+ - test/test_keynote.rb
80
+ - test/test_rapinoe.rb
81
+ - test/test_slide.rb