odf 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +5 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +76 -0
  8. data/Rakefile +6 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +8 -0
  11. data/lib/odf.rb +65 -0
  12. data/lib/odf/component/abstract.rb +23 -0
  13. data/lib/odf/component/content.rb +35 -0
  14. data/lib/odf/component/image_set.rb +42 -0
  15. data/lib/odf/component/manifest.rb +33 -0
  16. data/lib/odf/component/meta.rb +25 -0
  17. data/lib/odf/component/mime_type.rb +11 -0
  18. data/lib/odf/component/settings.rb +15 -0
  19. data/lib/odf/component/styles.rb +26 -0
  20. data/lib/odf/component/xml_component.rb +29 -0
  21. data/lib/odf/document/abstract.rb +67 -0
  22. data/lib/odf/document/presentation.rb +13 -0
  23. data/lib/odf/document/spreadsheet.rb +13 -0
  24. data/lib/odf/document/text.rb +17 -0
  25. data/lib/odf/element/abstract.rb +34 -0
  26. data/lib/odf/element/abstract_contenteable.rb +11 -0
  27. data/lib/odf/element/binary_data.rb +13 -0
  28. data/lib/odf/element/draw_frame.rb +50 -0
  29. data/lib/odf/element/draw_page.rb +15 -0
  30. data/lib/odf/element/draw_text_box.rb +38 -0
  31. data/lib/odf/element/heading.rb +18 -0
  32. data/lib/odf/element/image.rb +41 -0
  33. data/lib/odf/element/number.rb +14 -0
  34. data/lib/odf/element/paragraph.rb +14 -0
  35. data/lib/odf/element/table.rb +19 -0
  36. data/lib/odf/element/table_cell.rb +30 -0
  37. data/lib/odf/element/table_row.rb +16 -0
  38. data/lib/odf/element/text_list.rb +21 -0
  39. data/lib/odf/element/text_list_item.rb +29 -0
  40. data/lib/odf/utils/file.rb +45 -0
  41. data/lib/odf/utils/xml.rb +13 -0
  42. data/lib/odf/version.rb +3 -0
  43. data/odf.gemspec +32 -0
  44. data/templates/default_style.xml +2 -0
  45. metadata +185 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c618b4ea9d37d5b03a96097f0de0e3b9abc3056c
4
+ data.tar.gz: 4f2517bbd3c2db27744ccec7dfcf9cf9cef02f9a
5
+ SHA512:
6
+ metadata.gz: 6cd614592cc7f05e84bfcadc5432195f14f044b930f47f3062b5eb790c7b8e6f1c3f76415c42c24719876b164fcc191e9b41280e9edbc125a66b8092a086f3b7
7
+ data.tar.gz: 4b7230485ef33647135a49dd09843d8dfe9839d43fa25ea983765d28f46d6d9f6c7bd32e623e3d80bd553d0ad8fbeea4307e2fc006b0373cb29a00ad5cd5457c
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.0
5
+ before_install: gem install bundler -v 1.13.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in odf.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Mehmet Emin İNAÇ
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,76 @@
1
+ # Odf(open document format)
2
+
3
+ Create `.odt`, `.ods` and `.odp` files with Ruby! For the information what is ODF please have a look at the specification [page](https://www.oasis-open.org/committees/tc_home.php).
4
+
5
+ **Note: ** This gem is still in progress and the API may change even in minor version update!
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'odf'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install odf
22
+
23
+ ## Usage
24
+
25
+ This gem provides 3 main classes for each document type. `Odf::Document::Text`, `Odf::Document::Spreadsheet` and `Odf::Document::Presentation`. You can instantiate any of them like so:
26
+
27
+ ```ruby
28
+ document = Odf::Document::Text.new
29
+ ```
30
+
31
+ After you create the document, you can add elements to it. Here we add a paragraph to our document:
32
+
33
+ ```ruby
34
+ document = Odf::Document::Text.new
35
+ document.add_paragraph('Tülaay, ne olursun geri dön.')
36
+ ```
37
+
38
+ For available elements you can add into your document please have a look at the `lib/element` directory.
39
+
40
+ You can also add meta information to your document like so:
41
+
42
+ ```ruby
43
+ document = Odf::Document::Text.new
44
+ document.creator = 'Twentify'
45
+ ```
46
+
47
+ ### Serialization?
48
+
49
+ You can either serialize your document directly to file system like so:
50
+
51
+ ```ruby
52
+ document = Odf::Document::Text.new
53
+ document.serialize('path_to_serialize')
54
+ ```
55
+
56
+ or get an output stream to work on it like so:
57
+
58
+ ```ruby
59
+ document = Odf::Document::Text.new
60
+ document.to_blob
61
+ ```
62
+
63
+ ## Development
64
+
65
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
66
+
67
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
68
+
69
+ ## Contributing
70
+
71
+ Bug reports and pull requests are welcome on GitHub at https://github.com/meinac/odf.
72
+
73
+
74
+ ## License
75
+
76
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "odf"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/lib/odf.rb ADDED
@@ -0,0 +1,65 @@
1
+ require 'open-uri'
2
+ require 'set'
3
+ require 'openssl'
4
+ require 'zip'
5
+ require 'nokogiri'
6
+ require 'mimemagic'
7
+
8
+ require 'odf/version'
9
+ require 'odf/utils/file'
10
+ require 'odf/utils/xml'
11
+
12
+ require 'odf/element/abstract'
13
+ require 'odf/element/abstract_contenteable'
14
+ require 'odf/element/binary_data'
15
+ require 'odf/element/draw_page'
16
+ require 'odf/element/draw_frame'
17
+ require 'odf/element/draw_text_box'
18
+ require 'odf/element/heading'
19
+ require 'odf/element/image'
20
+ require 'odf/element/number'
21
+ require 'odf/element/paragraph'
22
+ require 'odf/element/table'
23
+ require 'odf/element/table_cell'
24
+ require 'odf/element/table_row'
25
+ require 'odf/element/text_list'
26
+ require 'odf/element/text_list_item'
27
+
28
+ require 'odf/component/xml_component'
29
+ require 'odf/component/abstract'
30
+ require 'odf/component/content'
31
+ require 'odf/component/image_set'
32
+ require 'odf/component/manifest'
33
+ require 'odf/component/meta'
34
+ require 'odf/component/mime_type'
35
+ require 'odf/component/settings'
36
+ require 'odf/component/styles'
37
+
38
+ require 'odf/document/abstract'
39
+ require 'odf/document/presentation'
40
+ require 'odf/document/spreadsheet'
41
+ require 'odf/document/text'
42
+
43
+ module Odf
44
+
45
+ ROOT_PATH = File.expand_path("../..", __FILE__)
46
+ TEMPLATE_PATH = "#{ROOT_PATH}/templates".freeze
47
+ DEFAULT_STYLE = "#{TEMPLATE_PATH}/default_style.xml".freeze
48
+
49
+ def self.configure(&block)
50
+ block.call
51
+ end
52
+
53
+ def self.styles=(val)
54
+ @styles = val
55
+ end
56
+
57
+ def self.styles
58
+ File.read(@styles || DEFAULT_STYLE)
59
+ end
60
+
61
+ def self.creator
62
+ @creator
63
+ end
64
+
65
+ end
@@ -0,0 +1,23 @@
1
+ module Odf::Component
2
+ class Abstract
3
+
4
+ attr_reader :document
5
+
6
+ def initialize(document)
7
+ @document = document
8
+ end
9
+
10
+ def content
11
+ raise NotImplementedError.new('Subclasess should implement this method!')
12
+ end
13
+
14
+ def name
15
+ self.class::NAME
16
+ end
17
+
18
+ def inspect
19
+ to_s
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,35 @@
1
+ # Holds the xml of content.xml file
2
+ module Odf::Component
3
+ class Content < Abstract
4
+ include XmlComponent
5
+
6
+ NAME = 'content.xml'.freeze
7
+
8
+ attr_reader :root
9
+
10
+ private
11
+ def initialize_xml
12
+ super
13
+ xml.root = xml.create_element(
14
+ 'office:document-content',
15
+ {
16
+ 'xmlns:office' => 'urn:oasis:names:tc:opendocument:xmlns:office:1.0',
17
+ 'xmlns:style' => 'urn:oasis:names:tc:opendocument:xmlns:style:1.0',
18
+ 'xmlns:text' => 'urn:oasis:names:tc:opendocument:xmlns:text:1.0',
19
+ 'xmlns:table' => 'urn:oasis:names:tc:opendocument:xmlns:table:1.0',
20
+ 'xmlns:draw' => 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0',
21
+ 'xmlns:fo' => 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0',
22
+ 'xmlns:xlink' => 'http://www.w3.org/1999/xlink',
23
+ 'xmlns:dc' => 'http://purl.org/dc/elements/1.1/',
24
+ 'xmlns:meta' => 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0',
25
+ 'xmlns:number' => 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0',
26
+ 'xmlns:svg' => 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0'
27
+ }
28
+ )
29
+ body = xml.create_element('office:body')
30
+ @root = body.add_child(xml.create_element(document.wrapper))
31
+ xml.root.add_child(body)
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,42 @@
1
+ module Odf::Component
2
+ class ImageSet < Abstract
3
+ class Image
4
+
5
+ attr_reader :uri, :path, :content_type
6
+
7
+ def initialize(uri)
8
+ @uri = uri
9
+ digest = OpenSSL::Digest::MD5.hexdigest(uri)
10
+ @path = "Pictures/#{digest}"
11
+ end
12
+
13
+ def save
14
+ @content, @content_type = Odf::Utils::File.fetch_image(self)
15
+ end
16
+
17
+ def content
18
+ @content || (save && @content)
19
+ end
20
+ end
21
+
22
+ attr_reader :images
23
+
24
+ def initialize(*args)
25
+ super
26
+ @images = Set.new
27
+ end
28
+
29
+ def <<(path)
30
+ image = Image.new(path)
31
+ images << image
32
+ image.path
33
+ end
34
+
35
+ def each(&block)
36
+ images.each do |image|
37
+ block.call(image)
38
+ end
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,33 @@
1
+ module Odf::Component
2
+ class Manifest < Abstract
3
+ include XmlComponent
4
+
5
+ NAME = 'META-INF/manifest.xml'.freeze
6
+
7
+ private
8
+ def initialize_xml
9
+ super
10
+ xml.root = xml.create_element('manifest:manifest', 'xmlns:manifest' => 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0')
11
+ self_element = xml.create_element('manifest:file-entry', 'manifest:media-type' => document.media_type, 'manifest:full-path' => '/')
12
+ xml.root.add_child(self_element)
13
+ content_element = xml.create_element('manifest:file-entry', 'manifest:media-type' => 'text/xml', 'manifest:full-path' => 'content.xml')
14
+ xml.root.add_child(content_element)
15
+ styles_xml = xml.create_element('manifest:file-entry', 'manifest:media-type' => 'text/xml', 'manifest:full-path' => 'styles.xml')
16
+ xml.root.add_child(styles_xml)
17
+ settings_xml = xml.create_element('manifest:file-entry', 'manifest:media-type' => 'text/xml', 'manifest:full-path' => 'settings.xml')
18
+ xml.root.add_child(settings_xml)
19
+ meta_xml = xml.create_element('manifest:file-entry', 'manifest:media-type' => 'text/xml', 'manifest:full-path' => 'meta.xml')
20
+ xml.root.add_child(meta_xml)
21
+ end
22
+
23
+ # Finalize XML
24
+ def wrap_xml
25
+ # Insert document images
26
+ document.image_set.images.each do |image|
27
+ image_element = xml.create_element('manifest:file-entry', 'manifest:media-type' => image.content_type, 'manifest:full-path' => image.path)
28
+ xml.root.add_child(image_element)
29
+ end
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,25 @@
1
+ module Odf::Component
2
+ class Meta < Abstract
3
+ include XmlComponent
4
+
5
+ TIME_FORMAT = '%Y-%m-%dT%H:%M:%S'.freeze
6
+ NAME = 'meta.xml'.freeze
7
+
8
+ private
9
+ def wrap_xml
10
+ xml.root = xml.create_element(
11
+ 'office:document-meta',
12
+ {
13
+ 'xmlns:office' => 'urn:oasis:names:tc:opendocument:xmlns:office:1.0',
14
+ 'xmlns:dc' => 'http://purl.org/dc/elements/1.1/',
15
+ 'xmlns:meta' => 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'
16
+ }
17
+ )
18
+ meta_element = xml.add_element('office:meta')
19
+ xml.add_element_into(meta_element, 'meta:generator', 'Ruby-ODF-Gem')
20
+ xml.add_element_into(meta_element, 'dc:creator', document.creator) if document.creator
21
+ xml.add_element_into(meta_element, 'meta:creation-date', Time.now.strftime(TIME_FORMAT))
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,11 @@
1
+ module Odf::Component
2
+ class MimeType < Abstract
3
+
4
+ NAME = 'mimetype'.freeze
5
+
6
+ def content
7
+ document.media_type
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module Odf::Component
2
+ class Settings < Abstract
3
+ include XmlComponent
4
+
5
+ NAME = 'settings.xml'.freeze
6
+
7
+ private
8
+ def initialize_xml
9
+ super
10
+ xml.root = xml.create_element('office:document-settings', 'xmlns:office' => 'urn:oasis:names:tc:opendocument:xmlns:office:1.0')
11
+ xml.add_element('office:settings')
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ module Odf::Component
2
+ class Styles < Abstract
3
+ include XmlComponent
4
+
5
+ NAME = 'styles.xml'.freeze
6
+
7
+ def content
8
+ Odf.styles
9
+ end
10
+
11
+ private
12
+ def initialize_xml
13
+ super
14
+ xml.root = xml.create_element('office:document-styles', 'xmlns:office' => 'urn:oasis:names:tc:opendocument:xmlns:office:1.0')
15
+ font_decls = xml.create_element('office:font-face-decls')
16
+ times_nr = xml.create_element('style:font-face', { 'style:name' => 'Times New Roman', 'svg:font-family' => '&apos;Times New Roman&apos;', 'style:font-family-generic' => 'roman', 'style:font-pitch' => 'variable' })
17
+ arial = xml.create_element('style:font-face', { 'style:name' => 'Arial', 'svg:font-family' => '&apos;Arial&apos;', 'style:font-family-generic' => 'swiss', 'style:font-pitch' => 'variable' })
18
+ arial_uc = xml.create_element('style:font-face', { 'style:name' => 'Arial Unicode MS', 'svg:font-family' => '&apos;Arial Unicode MS&apos;', 'style:font-family-generic' => 'system', 'style:font-pitch' => 'variable' })
19
+ font_decls.add_child(times_nr)
20
+ font_decls.add_child(arial)
21
+ font_decls.add_child(arial_uc)
22
+ xml.root.add_child(font_decls)
23
+ end
24
+
25
+ end
26
+ end