Initial project setup

This commit is contained in:
2025-12-02 10:23:52 +01:00
commit 50c9c20eca
16 changed files with 340 additions and 0 deletions

12
.gitignore vendored Normal file
View 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
View 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
View File

@@ -0,0 +1,5 @@
# frozen_string_literal: true
source "https://rubygems.org"
gemspec

21
LICENSE.txt Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@@ -0,0 +1,5 @@
# frozen_string_literal: true
module Ezdoc
VERSION = "0.0.1"
end

View 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

View 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

View 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
View 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
View File

@@ -0,0 +1,5 @@
# frozen_string_literal: true
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
require "ezdoc"
require "minitest/autorun"