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