Initial project setup
This commit is contained in:
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
*.gem
|
||||||
|
*.rbc
|
||||||
|
.bundle
|
||||||
|
.config
|
||||||
|
coverage
|
||||||
|
pkg
|
||||||
|
spec/reports
|
||||||
|
tmp
|
||||||
|
.rspec_status
|
||||||
|
Gemfile.lock
|
||||||
|
*.docx
|
||||||
|
*.docx#
|
||||||
22
.rubocop.yml
Normal file
22
.rubocop.yml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
AllCops:
|
||||||
|
TargetRubyVersion: 3.0
|
||||||
|
NewCops: enable
|
||||||
|
SuggestExtensions: false
|
||||||
|
|
||||||
|
Style/StringLiterals:
|
||||||
|
EnforcedStyle: double_quotes
|
||||||
|
|
||||||
|
Style/StringLiteralsInInterpolation:
|
||||||
|
EnforcedStyle: double_quotes
|
||||||
|
|
||||||
|
Style/Documentation:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Layout/LineLength:
|
||||||
|
Max: 120
|
||||||
|
|
||||||
|
Metrics:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Gemspec/DevelopmentDependencies:
|
||||||
|
Enabled: false
|
||||||
5
Gemfile
Normal file
5
Gemfile
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
source "https://rubygems.org"
|
||||||
|
|
||||||
|
gemspec
|
||||||
21
LICENSE.txt
Normal file
21
LICENSE.txt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 Mathias
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
33
README.md
Normal file
33
README.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Ezdoc
|
||||||
|
|
||||||
|
A Ruby gem for working with docx files.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Add this line to your application's Gemfile:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
gem 'ezdoc'
|
||||||
|
```
|
||||||
|
|
||||||
|
And then execute:
|
||||||
|
|
||||||
|
$ bundle install
|
||||||
|
|
||||||
|
Or install it yourself as:
|
||||||
|
|
||||||
|
$ gem install ezdoc
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
require 'ezdoc'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
After checking out the repo, run `bundle install` to install dependencies. Then, run `rake spec` to run the tests.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
The gem is available as open source under the terms of the [MIT License](LICENSE.txt).
|
||||||
15
Rakefile
Normal file
15
Rakefile
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "bundler/gem_tasks"
|
||||||
|
require "rake/testtask"
|
||||||
|
require "rubocop/rake_task"
|
||||||
|
|
||||||
|
Rake::TestTask.new(:test) do |t|
|
||||||
|
t.libs << "test"
|
||||||
|
t.libs << "lib"
|
||||||
|
t.test_files = FileList["test/**/*_test.rb"]
|
||||||
|
end
|
||||||
|
|
||||||
|
RuboCop::RakeTask.new
|
||||||
|
|
||||||
|
task default: %i[test rubocop]
|
||||||
26
ezdoc.gemspec
Normal file
26
ezdoc.gemspec
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative "lib/ezdoc/version"
|
||||||
|
|
||||||
|
Gem::Specification.new do |spec|
|
||||||
|
spec.name = "ezdoc"
|
||||||
|
spec.version = Ezdoc::VERSION
|
||||||
|
spec.authors = ["Mathias"]
|
||||||
|
spec.summary = "A Ruby gem for working with docx files"
|
||||||
|
spec.description = "Easy document manipulation for docx files in Ruby"
|
||||||
|
spec.homepage = "https://github.com/mathias/ezdoc"
|
||||||
|
spec.license = "MIT"
|
||||||
|
spec.required_ruby_version = ">= 3.0.0"
|
||||||
|
|
||||||
|
spec.files = Dir.glob("{lib}/**/*") + %w[README.md LICENSE.txt]
|
||||||
|
spec.require_paths = ["lib"]
|
||||||
|
|
||||||
|
spec.add_dependency "nokogiri", "~> 1.18"
|
||||||
|
spec.add_dependency "rubyzip", "~> 2.3"
|
||||||
|
|
||||||
|
spec.add_development_dependency "bundler", "~> 2.0"
|
||||||
|
spec.add_development_dependency "minitest", "~> 5.0"
|
||||||
|
spec.add_development_dependency "rake", "~> 13.0"
|
||||||
|
spec.add_development_dependency "rubocop", "~> 1.69"
|
||||||
|
spec.metadata["rubygems_mfa_required"] = "true"
|
||||||
|
end
|
||||||
14
lib/ezdoc.rb
Normal file
14
lib/ezdoc.rb
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "nokogiri"
|
||||||
|
|
||||||
|
require_relative "ezdoc/version"
|
||||||
|
require_relative "ezdoc/xml/content_types"
|
||||||
|
require_relative "ezdoc/xml/relationships"
|
||||||
|
require_relative "ezdoc/xml/document_xml"
|
||||||
|
require_relative "ezdoc/package"
|
||||||
|
require_relative "ezdoc/document"
|
||||||
|
|
||||||
|
module Ezdoc
|
||||||
|
class Error < StandardError; end
|
||||||
|
end
|
||||||
26
lib/ezdoc/document.rb
Normal file
26
lib/ezdoc/document.rb
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Ezdoc
|
||||||
|
class Document
|
||||||
|
attr_reader :content
|
||||||
|
|
||||||
|
def self.create(path, &block)
|
||||||
|
doc = new
|
||||||
|
block.call(doc)
|
||||||
|
doc.save(path)
|
||||||
|
doc
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@content = []
|
||||||
|
end
|
||||||
|
|
||||||
|
def text(value)
|
||||||
|
@content << { text: value }
|
||||||
|
end
|
||||||
|
|
||||||
|
def save(path)
|
||||||
|
Package.new(self).save(path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
38
lib/ezdoc/package.rb
Normal file
38
lib/ezdoc/package.rb
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "zip"
|
||||||
|
|
||||||
|
module Ezdoc
|
||||||
|
class Package
|
||||||
|
def initialize(document)
|
||||||
|
@document = document
|
||||||
|
end
|
||||||
|
|
||||||
|
def save(path)
|
||||||
|
Zip::File.open(path, Zip::File::CREATE) do |zipfile|
|
||||||
|
zipfile.get_output_stream("[Content_Types].xml") { |f| f.write(content_types_xml) }
|
||||||
|
zipfile.get_output_stream("_rels/.rels") { |f| f.write(relationships_xml) }
|
||||||
|
zipfile.get_output_stream("word/_rels/document.xml.rels") { |f| f.write(document_relationships_xml) }
|
||||||
|
zipfile.get_output_stream("word/document.xml") { |f| f.write(document_xml) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def content_types_xml
|
||||||
|
Xml::ContentTypes.new.to_xml
|
||||||
|
end
|
||||||
|
|
||||||
|
def relationships_xml
|
||||||
|
Xml::Relationships.new.to_xml
|
||||||
|
end
|
||||||
|
|
||||||
|
def document_relationships_xml
|
||||||
|
Xml::DocumentRelationships.new.to_xml
|
||||||
|
end
|
||||||
|
|
||||||
|
def document_xml
|
||||||
|
Xml::DocumentXml.new(@document.content).to_xml
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
5
lib/ezdoc/version.rb
Normal file
5
lib/ezdoc/version.rb
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Ezdoc
|
||||||
|
VERSION = "0.0.1"
|
||||||
|
end
|
||||||
23
lib/ezdoc/xml/content_types.rb
Normal file
23
lib/ezdoc/xml/content_types.rb
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Ezdoc
|
||||||
|
module Xml
|
||||||
|
class ContentTypes
|
||||||
|
NAMESPACE = "http://schemas.openxmlformats.org/package/2006/content-types"
|
||||||
|
|
||||||
|
def to_xml
|
||||||
|
builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
|
||||||
|
xml.Types(xmlns: NAMESPACE) do
|
||||||
|
xml.Default(Extension: "rels", ContentType: "application/vnd.openxmlformats-package.relationships+xml")
|
||||||
|
xml.Default(Extension: "xml", ContentType: "application/xml")
|
||||||
|
xml.Override(
|
||||||
|
PartName: "/word/document.xml",
|
||||||
|
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
builder.to_xml
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
34
lib/ezdoc/xml/document_xml.rb
Normal file
34
lib/ezdoc/xml/document_xml.rb
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Ezdoc
|
||||||
|
module Xml
|
||||||
|
class DocumentXml
|
||||||
|
NAMESPACES = {
|
||||||
|
"xmlns:w" => "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
||||||
|
"xmlns:r" => "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
def initialize(content)
|
||||||
|
@content = content
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_xml
|
||||||
|
builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
|
||||||
|
xml.document(NAMESPACES) do
|
||||||
|
xml.parent.namespace = xml.parent.namespace_definitions.find { |ns| ns.prefix == "w" }
|
||||||
|
xml["w"].body do
|
||||||
|
@content.each do |item|
|
||||||
|
xml["w"].p do
|
||||||
|
xml["w"].r do
|
||||||
|
xml["w"].t item[:text]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
builder.to_xml
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
33
lib/ezdoc/xml/relationships.rb
Normal file
33
lib/ezdoc/xml/relationships.rb
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Ezdoc
|
||||||
|
module Xml
|
||||||
|
class Relationships
|
||||||
|
NAMESPACE = "http://schemas.openxmlformats.org/package/2006/relationships"
|
||||||
|
|
||||||
|
def to_xml
|
||||||
|
builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
|
||||||
|
xml.Relationships(xmlns: NAMESPACE) do
|
||||||
|
xml.Relationship(
|
||||||
|
Id: "rId1",
|
||||||
|
Type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
|
||||||
|
Target: "word/document.xml"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
builder.to_xml
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class DocumentRelationships
|
||||||
|
NAMESPACE = "http://schemas.openxmlformats.org/package/2006/relationships"
|
||||||
|
|
||||||
|
def to_xml
|
||||||
|
builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
|
||||||
|
xml.Relationships(xmlns: NAMESPACE)
|
||||||
|
end
|
||||||
|
builder.to_xml
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
28
test/ezdoc_test.rb
Normal file
28
test/ezdoc_test.rb
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "test_helper"
|
||||||
|
require "tempfile"
|
||||||
|
require "zip"
|
||||||
|
|
||||||
|
class EzdocTest < Minitest::Test
|
||||||
|
def test_creates_valid_docx_with_hello_world
|
||||||
|
Tempfile.create(["test", ".docx"]) do |file|
|
||||||
|
Ezdoc::Document.create(file.path) do |doc|
|
||||||
|
doc.text "Hello World"
|
||||||
|
end
|
||||||
|
|
||||||
|
assert File.exist?(file.path)
|
||||||
|
assert File.size(file.path).positive?
|
||||||
|
|
||||||
|
Zip::File.open(file.path) do |zip|
|
||||||
|
assert zip.find_entry("[Content_Types].xml")
|
||||||
|
assert zip.find_entry("_rels/.rels")
|
||||||
|
assert zip.find_entry("word/document.xml")
|
||||||
|
assert zip.find_entry("word/_rels/document.xml.rels")
|
||||||
|
|
||||||
|
document_xml = zip.read("word/document.xml")
|
||||||
|
assert_includes document_xml, "Hello World"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
5
test/test_helper.rb
Normal file
5
test/test_helper.rb
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
||||||
|
require "ezdoc"
|
||||||
|
require "minitest/autorun"
|
||||||
Reference in New Issue
Block a user