udrs 0.1.0
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 +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +57 -0
- data/lib/udrs.rb +3 -0
- data/lib/udrs/components.rb +11 -0
- data/lib/udrs/components/code.rb +11 -0
- data/lib/udrs/components/container.rb +11 -0
- data/lib/udrs/components/footer.rb +6 -0
- data/lib/udrs/components/header.rb +15 -0
- data/lib/udrs/components/logo.rb +12 -0
- data/lib/udrs/components/page_end.rb +6 -0
- data/lib/udrs/components/raw.rb +11 -0
- data/lib/udrs/components/spacer.rb +11 -0
- data/lib/udrs/components/t_text.rb +12 -0
- data/lib/udrs/components/table.rb +70 -0
- data/lib/udrs/components/text.rb +33 -0
- data/lib/udrs/document.rb +109 -0
- data/lib/udrs/engine.rb +14 -0
- data/lib/udrs/engine/rails_helper.rb +11 -0
- data/lib/udrs/engine/template_renderer.rb +14 -0
- data/lib/udrs/renderers.rb +2 -0
- data/lib/udrs/renderers/base.rb +17 -0
- data/lib/udrs/renderers/escp_renderer.rb +156 -0
- data/lib/udrs/renderers/escp_renderer/font.rb +84 -0
- data/lib/udrs/renderers/escp_renderer/line.rb +77 -0
- data/lib/udrs/renderers/escp_renderer/table.rb +70 -0
- data/lib/udrs/renderers/pdf_renderer.rb +180 -0
- data/lib/udrs/version.rb +3 -0
- data/udrs.gemspec +30 -0
- metadata +199 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c2c17a09654a55b9b2e30ee71b9f6f5d940f32e8
|
4
|
+
data.tar.gz: 7ece63f00f97b75c1e955679c0f55a681a5802b3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: da98fe1ffe17900362377dc6bc3baeab6807578b8746ec96f21fefde97af0f72db7a65a7354a92591879e57a1432c0e53ff89d41c0a1a210f34c9b2875dcf8c3
|
7
|
+
data.tar.gz: 8a944d33c23d1ce309e78c65523ba15951d25fca0fbf8c2eab62c2b5b9df8304c6e0672525c400a1e9ab1ae44b50b676b8d9913b01524a2de575cb3c09a95fcb
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Michon van Dooren
|
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,57 @@
|
|
1
|
+
# UDRS
|
2
|
+
|
3
|
+
UDRS stands for the Universal Document Rendering System. This is an ambition name, and the gem does not in any way live up to the expectations that the name creates.
|
4
|
+
|
5
|
+
What it does do, in short, is allow you to write a single template for a file, and then render that template to a number of formats.
|
6
|
+
|
7
|
+
Currently, the following formats are supported:
|
8
|
+
- PDF
|
9
|
+
- ESC/P (Epson receipt printers)
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem 'udrs'
|
17
|
+
```
|
18
|
+
|
19
|
+
And then execute:
|
20
|
+
|
21
|
+
$ bundle
|
22
|
+
|
23
|
+
Or install it yourself as:
|
24
|
+
|
25
|
+
$ gem install udrs
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
Create a view in the normal location, with the `.udrs` extension. The use the methods provided in doc to create your document.
|
30
|
+
|
31
|
+
Example template:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
udrs_document do |doc|
|
35
|
+
doc.section('Hello world!')
|
36
|
+
doc.subsection('Introduction to the world')
|
37
|
+
doc.text('Lorem ipsum dolor sit amet')
|
38
|
+
|
39
|
+
doc.table([:fit, :expand, :fit]) do |table|
|
40
|
+
table.row(10, 'Lorem ipsum', 12.34)
|
41
|
+
table.row do |row|
|
42
|
+
row.cell(10)
|
43
|
+
row.cell('Lorem ipsum dolor sit amet', style: :bold)
|
44
|
+
row.cell(-12)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
doc.footer do
|
49
|
+
doc.text('Copyright 1970 Anonymous', size: :small)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
## License
|
55
|
+
|
56
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
57
|
+
|
data/lib/udrs.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'udrs/components/code'
|
2
|
+
require 'udrs/components/container'
|
3
|
+
require 'udrs/components/footer'
|
4
|
+
require 'udrs/components/header'
|
5
|
+
require 'udrs/components/logo'
|
6
|
+
require 'udrs/components/page_end'
|
7
|
+
require 'udrs/components/raw'
|
8
|
+
require 'udrs/components/spacer'
|
9
|
+
require 'udrs/components/table'
|
10
|
+
require 'udrs/components/text'
|
11
|
+
require 'udrs/components/t_text'
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module UDRS
|
2
|
+
module Components
|
3
|
+
class Header
|
4
|
+
attr_reader :text, :level
|
5
|
+
|
6
|
+
LEVELS = 1..3
|
7
|
+
|
8
|
+
def initialize(text, level = 1)
|
9
|
+
@text = text.to_s
|
10
|
+
fail ArgumentError, "Invalid level: #{level}" unless LEVELS.include?(level)
|
11
|
+
@level = level
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module UDRS
|
2
|
+
module Components
|
3
|
+
class Table
|
4
|
+
attr_reader :columns, :rows
|
5
|
+
|
6
|
+
COLUMN_SIZES = %i(fit expand hide)
|
7
|
+
|
8
|
+
def initialize(*columns, &block)
|
9
|
+
@columns = columns
|
10
|
+
invalid = (columns.reject { |c| c.is_a?(Fixnum) } - COLUMN_SIZES).uniq
|
11
|
+
fail ArgumentError, "Invalid column size(s): #{invalid.join(', ')}" unless invalid.empty?
|
12
|
+
|
13
|
+
@rows = []
|
14
|
+
block.call(self)
|
15
|
+
end
|
16
|
+
|
17
|
+
def row(*args, &block)
|
18
|
+
@rows << Row.new(self, *args, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_column_widths
|
22
|
+
return columns.each_with_index.map do |column, i|
|
23
|
+
case column
|
24
|
+
# Fixed width
|
25
|
+
when Fixnum
|
26
|
+
next [column, column, column]
|
27
|
+
|
28
|
+
# Fit
|
29
|
+
when :fit
|
30
|
+
size = rows.map { |r| r.cells[i] }.map(&:text).map(&:size).max
|
31
|
+
next [size, size, size]
|
32
|
+
|
33
|
+
# Expand
|
34
|
+
when :expand
|
35
|
+
size = rows.map { |r| r.cells[i] }.map(&:text).map(&:size).max
|
36
|
+
next [0, size, 9999]
|
37
|
+
|
38
|
+
# Hide
|
39
|
+
when :hide
|
40
|
+
next [0, 0, 0]
|
41
|
+
|
42
|
+
else
|
43
|
+
fail ArgumentError, "Cannot calculate column width for #{column}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Row
|
50
|
+
attr_reader :cells
|
51
|
+
|
52
|
+
def initialize(table, *args, &block)
|
53
|
+
options = {}
|
54
|
+
options = args.pop if args.last.is_a?(Hash)
|
55
|
+
|
56
|
+
@cells = []
|
57
|
+
args.each { |c| cell(c, options) }
|
58
|
+
block.call(self) if block
|
59
|
+
|
60
|
+
if @cells.size != table.columns.size
|
61
|
+
fail ArgumentError, "Row contains #{cells.size} cells, but #{table.columns.size} are required"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def cell(text, options = {})
|
66
|
+
@cells << Text.new(text, options)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'attribute_predicates'
|
2
|
+
|
3
|
+
module UDRS
|
4
|
+
module Components
|
5
|
+
class Text
|
6
|
+
attr_reader :text, :is_bold, :is_italic, :is_underline, :size, :alignment
|
7
|
+
|
8
|
+
SIZES = %i(tiny small normal medium large huge)
|
9
|
+
ALIGNENTS = %i(left center right)
|
10
|
+
|
11
|
+
def initialize(text, options = {})
|
12
|
+
@text = text.to_s
|
13
|
+
|
14
|
+
# Text size
|
15
|
+
@size = :normal
|
16
|
+
@size = options[:size] if options[:size].present?
|
17
|
+
fail ArgumentError, "Invalid size: #{@size}" unless SIZES.include?(@size)
|
18
|
+
|
19
|
+
# Style(s)
|
20
|
+
style = [*options[:style]]
|
21
|
+
@is_bold = style.delete(:bold)
|
22
|
+
@is_italic = style.delete(:italic)
|
23
|
+
@is_underline = style.delete(:underline)
|
24
|
+
fail ArgumentError, "Invalid style(s): #{style.join(', ')}" unless style.empty?
|
25
|
+
|
26
|
+
# Alignment
|
27
|
+
@alignment = :left
|
28
|
+
@alignment = options[:align] if options[:align].present?
|
29
|
+
fail ArgumentError, "Invalid alignment: #{@alignment}" unless ALIGNENTS.include?(@alignment)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'udrs/components'
|
2
|
+
require 'udrs/renderers'
|
3
|
+
|
4
|
+
require 'attribute_predicates'
|
5
|
+
|
6
|
+
module UDRS
|
7
|
+
class Document
|
8
|
+
attr_reader :is_rendering
|
9
|
+
|
10
|
+
TYPES = %i(pdf escp)
|
11
|
+
|
12
|
+
def initialize(type)
|
13
|
+
fail ArgumentError, "Unknown udrs type #{type}" unless TYPES.include?(type)
|
14
|
+
@type = type
|
15
|
+
case type
|
16
|
+
when :pdf
|
17
|
+
@renderer = Renderers::PDFRenderer.new
|
18
|
+
when :escp
|
19
|
+
@renderer = Renderers::ESCPRenderer.new
|
20
|
+
end
|
21
|
+
|
22
|
+
@container = Components::Container.new
|
23
|
+
@rendering = false
|
24
|
+
end
|
25
|
+
|
26
|
+
# Check the document type
|
27
|
+
def pdf?
|
28
|
+
return @type == :pdf
|
29
|
+
end
|
30
|
+
def escp?
|
31
|
+
return @type == :escp
|
32
|
+
end
|
33
|
+
|
34
|
+
# Add components
|
35
|
+
def end_page(*args)
|
36
|
+
add_component(Components::PageEnd.new(*args))
|
37
|
+
end
|
38
|
+
def spacer(*args)
|
39
|
+
add_component(Components::Spacer.new(*args))
|
40
|
+
end
|
41
|
+
def section(txt)
|
42
|
+
add_component(Components::Header.new(txt, 1))
|
43
|
+
end
|
44
|
+
def subsection(txt)
|
45
|
+
add_component(Components::Header.new(txt, 2))
|
46
|
+
end
|
47
|
+
def subsubsection(txt)
|
48
|
+
add_component(Components::Header.new(txt, 3))
|
49
|
+
end
|
50
|
+
def text(*args)
|
51
|
+
add_component(Components::Text.new(*args))
|
52
|
+
end
|
53
|
+
def ttext(*args)
|
54
|
+
add_component(Components::TText.new(*args))
|
55
|
+
end
|
56
|
+
def logo(*args)
|
57
|
+
add_component(Components::Logo.new(*args))
|
58
|
+
end
|
59
|
+
def code(*args)
|
60
|
+
add_component(Components::Code.new(*args))
|
61
|
+
end
|
62
|
+
def table(*args, &block)
|
63
|
+
add_component(Components::Table.new(*args, &block))
|
64
|
+
end
|
65
|
+
def raw(*args, &block)
|
66
|
+
add_component(Components::Raw.new(*args, &block))
|
67
|
+
end
|
68
|
+
def footer(*args, &block)
|
69
|
+
footer = Components::Footer.new(*args)
|
70
|
+
using_container(footer, &block)
|
71
|
+
add_component(footer)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Render the components using the renderer
|
75
|
+
def render
|
76
|
+
unless @rendered
|
77
|
+
@is_rendering = true
|
78
|
+
@rendered = @renderer.render(@container)
|
79
|
+
@is_rendering = false
|
80
|
+
end
|
81
|
+
return @rendered
|
82
|
+
end
|
83
|
+
def render!
|
84
|
+
@rendered = nil
|
85
|
+
return render
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
# If the rendering has already started, immediately render instead of caching
|
91
|
+
#
|
92
|
+
# This _should_ only happen in blocks passed to raw
|
93
|
+
def add_component(component)
|
94
|
+
if is_rendering?
|
95
|
+
@renderer.render_item(component)
|
96
|
+
else
|
97
|
+
@container.items << component
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Perform a block with the current container set to something else
|
102
|
+
def using_container(container, &block)
|
103
|
+
old_container = @container
|
104
|
+
@container = container
|
105
|
+
block.call
|
106
|
+
@container = old_container
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
data/lib/udrs/engine.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'udrs/engine/rails_helper'
|
2
|
+
require 'udrs/engine/template_renderer'
|
3
|
+
|
4
|
+
module UDRS
|
5
|
+
module Engine
|
6
|
+
class RailsEngine < Rails::Engine
|
7
|
+
ActionView::Base.send(:include, UDRS::Engine::RailsHelper)
|
8
|
+
ActionView::Template.register_template_handler(:udrs, UDRS::Engine::TemplateRenderer)
|
9
|
+
|
10
|
+
Mime::Type.register_alias('application/pdf', :pdf) if !Mime::Type.lookup_by_extension(:pdf)
|
11
|
+
Mime::Type.register_alias('application/octet-stream', :escp) if !Mime::Type.lookup_by_extension(:escp)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module UDRS
|
2
|
+
module Engine
|
3
|
+
class TemplateRenderer
|
4
|
+
def self.call(template)
|
5
|
+
return <<-END
|
6
|
+
output = #{template.source.strip}
|
7
|
+
@filename = "\#{controller.action_name}.\#{params[:format]}"
|
8
|
+
controller.response.headers['Content-Disposition'] = 'inline; filename="\#{@filename}"'
|
9
|
+
return output
|
10
|
+
END
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module UDRS
|
2
|
+
module Renderers
|
3
|
+
class Base
|
4
|
+
def render_item(item)
|
5
|
+
method_name = "render_#{item.class.name.demodulize.underscore}"
|
6
|
+
fail NotImplementedError, "Cannot render #{item.class.name}" unless respond_to?(method_name, true)
|
7
|
+
method(method_name).call(item)
|
8
|
+
end
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def render_items(items)
|
13
|
+
items.each(&method(:render_item))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'udrs/renderers/base'
|
2
|
+
require 'udrs/renderers/escp_renderer/font.rb'
|
3
|
+
require 'udrs/renderers/escp_renderer/line.rb'
|
4
|
+
require 'udrs/renderers/escp_renderer/table.rb'
|
5
|
+
|
6
|
+
module UDRS
|
7
|
+
module Renderers
|
8
|
+
# The renderer for ESC/P, short for Epson Standard Code for Printers
|
9
|
+
class ESCPRenderer < Base
|
10
|
+
NUL = 0.chr
|
11
|
+
EOT = 4.chr
|
12
|
+
ENQ = 5.chr
|
13
|
+
HT = 9.chr
|
14
|
+
LF = 10.chr
|
15
|
+
FF = 12.chr
|
16
|
+
CR = 13.chr
|
17
|
+
DLE = 16.chr
|
18
|
+
DC4 = 20.chr
|
19
|
+
CAN = 24.chr
|
20
|
+
ESC = 27.chr
|
21
|
+
FS = 28.chr
|
22
|
+
GS = 29.chr
|
23
|
+
|
24
|
+
CHARACTER_MAP = {
|
25
|
+
'€' => "\xD5",
|
26
|
+
'£' => "\x9C",
|
27
|
+
'¢' => "\xBD",
|
28
|
+
'«' => "\xAE",
|
29
|
+
'»' => "\xAF",
|
30
|
+
'→' => "\xAF",
|
31
|
+
'©' => "\xB8",
|
32
|
+
'®' => "\xA9",
|
33
|
+
}
|
34
|
+
|
35
|
+
CODE_NUM = 48 # The code num for PDF417
|
36
|
+
CODE_SIZE = 3
|
37
|
+
|
38
|
+
def render(container)
|
39
|
+
@buffer = ''
|
40
|
+
@buffer << "#{ESC}@" # Re-init printer
|
41
|
+
@buffer << "#{ESC}t#{19.chr}" # Reset character code table to PC858: Euro
|
42
|
+
@buffer << "#{ESC}M#{1.chr}" # Set the font
|
43
|
+
@buffer << "#{ESC}G#{0.chr}" # Set double-strike to off
|
44
|
+
apply_font_size(:normal)
|
45
|
+
apply_bold(false)
|
46
|
+
apply_underline(:off)
|
47
|
+
|
48
|
+
# Render the items
|
49
|
+
render_item(container)
|
50
|
+
render_page_end(nil)
|
51
|
+
|
52
|
+
# Open the cash drawer
|
53
|
+
@buffer << "#{ESC}p#{0.chr}#{100.chr}#{100.chr}"
|
54
|
+
|
55
|
+
# Replace special characters
|
56
|
+
buffer = @buffer.dup
|
57
|
+
CHARACTER_MAP.each do |char_orig, char_new|
|
58
|
+
buffer.gsub!(char_orig, char_new)
|
59
|
+
end
|
60
|
+
|
61
|
+
return buffer
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
##############################
|
67
|
+
# Render methods
|
68
|
+
##############################
|
69
|
+
|
70
|
+
def render_page_end(page_end)
|
71
|
+
# Cut the paper at page end
|
72
|
+
@buffer << "\n\n\n\n\n\x1DV1\n"
|
73
|
+
end
|
74
|
+
|
75
|
+
def render_spacer(spacer)
|
76
|
+
add_spacer
|
77
|
+
end
|
78
|
+
|
79
|
+
def render_header(header)
|
80
|
+
case header.level
|
81
|
+
when 1
|
82
|
+
add_spacer
|
83
|
+
add_line(header.text, size: :huge, bold: true, align: :center)
|
84
|
+
add_spacer
|
85
|
+
|
86
|
+
when 2
|
87
|
+
add_spacer
|
88
|
+
add_line(header.text, size: :large, bold: true)
|
89
|
+
|
90
|
+
when 3
|
91
|
+
add_line(header.text, size: :medium, bold: true)
|
92
|
+
|
93
|
+
else
|
94
|
+
fail ArgumentError, "Invalid header level: #{header.level}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def render_text(item)
|
99
|
+
add_line(item.text, text_to_options(item).merge(reflow: true))
|
100
|
+
end
|
101
|
+
|
102
|
+
def render_t_text(item)
|
103
|
+
add_line("#{item.title}: #{item.body}", size: :normal, bold: false, underline: false, reflow: true)
|
104
|
+
end
|
105
|
+
|
106
|
+
def render_logo(logo)
|
107
|
+
@buffer << "#{GS}(L#{6.chr}#{0.chr}#{48.chr}#{69.chr}#{32.chr}#{32.chr}#{1.chr}#{1.chr}"
|
108
|
+
@last_added = :logo
|
109
|
+
add_spacer
|
110
|
+
end
|
111
|
+
|
112
|
+
def render_code(code)
|
113
|
+
get_pl_ph = proc do |*params|
|
114
|
+
# From the docs:
|
115
|
+
# pL, pH specify the number of parameters after pH as (pL + pH*256)
|
116
|
+
return [params.size % 256, params.size / 256]
|
117
|
+
end
|
118
|
+
|
119
|
+
# The way to build a single line/setting of the code
|
120
|
+
part = proc do |function, *params|
|
121
|
+
fail ArgumentError unless params.all? { |p| p.is_a?(String) && p.length == 1 }
|
122
|
+
pl, ph = get_pl_ph.call(CODE_NUM, function, *params)
|
123
|
+
next "#{GS}(k#{pl.chr}#{ph.chr}#{CODE_NUM.chr}#{function.chr}#{params.join}"
|
124
|
+
end
|
125
|
+
|
126
|
+
@buffer << "\n"
|
127
|
+
@buffer << "#{ESC}a#{1.chr}" # Center
|
128
|
+
@buffer << part.call(67, CODE_SIZE.chr) # Set size
|
129
|
+
@buffer << part.call(69, 51.chr) # Set error correction
|
130
|
+
@buffer << part.call(80, 48.chr, *code.code.chars) # Set the code data
|
131
|
+
@buffer << part.call(81, 48.chr) # Start the print
|
132
|
+
@buffer << "#{ESC}a#{0.chr}" # End centering
|
133
|
+
|
134
|
+
@last_added = :code
|
135
|
+
end
|
136
|
+
|
137
|
+
def render_container(container)
|
138
|
+
render_items(container.items)
|
139
|
+
end
|
140
|
+
|
141
|
+
def render_footer(footer)
|
142
|
+
add_spacer
|
143
|
+
render_items(footer.items)
|
144
|
+
end
|
145
|
+
|
146
|
+
def render_raw(raw)
|
147
|
+
raw.block.call(@buffer)
|
148
|
+
end
|
149
|
+
|
150
|
+
def add_spacer
|
151
|
+
@buffer << ' ' * @line_width unless @last_added == :spacer
|
152
|
+
@last_added = :spacer
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module UDRS
|
2
|
+
module Renderers
|
3
|
+
# Font styling
|
4
|
+
class ESCPRenderer < Base
|
5
|
+
private
|
6
|
+
|
7
|
+
FONT_SIZE = {
|
8
|
+
tiny: [0b0100_0001, 56],
|
9
|
+
small: [0b0100_0001, 56],
|
10
|
+
normal: [0b0100_0001, 56],
|
11
|
+
medium: [0b0100_0000, 42],
|
12
|
+
large: [0b0111_0111, 28],
|
13
|
+
huge: [0b0111_0110, 21],
|
14
|
+
}
|
15
|
+
|
16
|
+
UNDERLINE = {
|
17
|
+
off: 0,
|
18
|
+
light: 1,
|
19
|
+
medium: 2,
|
20
|
+
}
|
21
|
+
|
22
|
+
def text_to_options(item)
|
23
|
+
return {
|
24
|
+
size: item.size,
|
25
|
+
bold: item.is_bold?,
|
26
|
+
underline: item.is_underline?,
|
27
|
+
align: item.alignment,
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def font(options = {}, &block)
|
32
|
+
font_size(options[:size] || @font_size) do
|
33
|
+
bold(options[:bold] || @font_bold) do
|
34
|
+
underline(options[:underline] || @font_underline) do
|
35
|
+
block.call
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def font_size(size, &block)
|
42
|
+
old_size = @font_size
|
43
|
+
apply_font_size(size)
|
44
|
+
block.call
|
45
|
+
apply_font_size(old_size)
|
46
|
+
end
|
47
|
+
|
48
|
+
def apply_font_size(size)
|
49
|
+
fail ArgumentError, "Invalid font size: #{size}" unless FONT_SIZE.key?(size)
|
50
|
+
@font_size = size
|
51
|
+
size = FONT_SIZE[size]
|
52
|
+
@buffer << "#{ESC}!#{size[0].chr}"
|
53
|
+
@line_width = size[1]
|
54
|
+
end
|
55
|
+
|
56
|
+
def bold(bold, &block)
|
57
|
+
old_bold = @font_bold
|
58
|
+
apply_bold(bold)
|
59
|
+
block.call
|
60
|
+
apply_bold(old_bold)
|
61
|
+
end
|
62
|
+
|
63
|
+
def apply_bold(status)
|
64
|
+
fail ArgumentError, 'Status must be a boolean' unless status == !!status
|
65
|
+
@font_bold = status
|
66
|
+
@buffer << "#{ESC}E#{status ? 1.chr : 0.chr}"
|
67
|
+
end
|
68
|
+
|
69
|
+
def underline(underline, &block)
|
70
|
+
old_underline = @font_underline
|
71
|
+
apply_underline(underline)
|
72
|
+
block.call
|
73
|
+
apply_underline(old_underline)
|
74
|
+
end
|
75
|
+
|
76
|
+
def apply_underline(underline)
|
77
|
+
underline = :medium if underline == !!underline
|
78
|
+
fail ArgumentError, 'Invalid underline value' unless UNDERLINE.key?(underline)
|
79
|
+
@font_underline = underline
|
80
|
+
@buffer << "#{ESC}_#{UNDERLINE[underline].chr}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'facets/string/word_wrap'
|
2
|
+
|
3
|
+
module UDRS
|
4
|
+
module Renderers
|
5
|
+
# Line methods
|
6
|
+
class ESCPRenderer < Base
|
7
|
+
private
|
8
|
+
|
9
|
+
def add_lines(lines, options = {})
|
10
|
+
lines.each { |l| add_line(l, options) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_line(line, options = {})
|
14
|
+
# Reflow if needed
|
15
|
+
line = line.gsub(/\s+/, ' ') if options[:reflow]
|
16
|
+
|
17
|
+
# If multiple lines, process each separately
|
18
|
+
if line.include?("\n")
|
19
|
+
line.split("\n").each { |line| add_line(line, options) }
|
20
|
+
return
|
21
|
+
end
|
22
|
+
|
23
|
+
# Apply the font
|
24
|
+
font(options) do
|
25
|
+
# Get width from options
|
26
|
+
width = options[:width] || @line_width
|
27
|
+
width = (width * @line_width).ceil if width.is_a?(Float)
|
28
|
+
fail ArgumentError, "Width cannot exceed max line width" if width > @line_width
|
29
|
+
|
30
|
+
# Get indent from options
|
31
|
+
indent = options[:indent] || 0
|
32
|
+
fail ArgumentError, "Indent cannot be larger than width" if indent >= width
|
33
|
+
width -= indent
|
34
|
+
|
35
|
+
# Process the line into lines
|
36
|
+
lines = line_to_block(line, width, options)
|
37
|
+
|
38
|
+
# Apply indent
|
39
|
+
lines.map! { |line| (' ' * indent) + line }
|
40
|
+
|
41
|
+
# Store lines
|
42
|
+
@buffer << lines.join
|
43
|
+
@last_added = :line
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def line_to_block(line, width, options = {})
|
48
|
+
line = line.to_s
|
49
|
+
if line.include?("\n")
|
50
|
+
lines = line.split("\n")
|
51
|
+
return lines.map { |line| line_to_block(line) }.flatten
|
52
|
+
end
|
53
|
+
|
54
|
+
# Wrap lines
|
55
|
+
lines = line.word_wrap(width).split("\n")
|
56
|
+
|
57
|
+
# Pad all lines
|
58
|
+
lines.map! do |line|
|
59
|
+
diff = width - line.size
|
60
|
+
case options[:align] || :left
|
61
|
+
when :left
|
62
|
+
next line + (' ' * diff)
|
63
|
+
when :right
|
64
|
+
next (' ' * diff) + line
|
65
|
+
when :center
|
66
|
+
half = diff / 2.0
|
67
|
+
next (' ' * half.ceil) + line + (' ' * half.floor)
|
68
|
+
else
|
69
|
+
fail ArgumentError, "Invalid alignment #{options[:align]}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
return lines
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module UDRS
|
2
|
+
module Renderers
|
3
|
+
# Tables
|
4
|
+
class ESCPRenderer < Base
|
5
|
+
private
|
6
|
+
|
7
|
+
def render_table(table)
|
8
|
+
add_spacer
|
9
|
+
|
10
|
+
# Get the column widths
|
11
|
+
column_widths = _calculate_table_column_widths(table)
|
12
|
+
|
13
|
+
# For each of the rows, render each cell according to the column with + cell properties
|
14
|
+
table.rows.each do |row|
|
15
|
+
# Get the non-hidden cells + their blocks
|
16
|
+
cells = []
|
17
|
+
parts = []
|
18
|
+
column_widths.zip(row.cells).each do |width, cell|
|
19
|
+
next if width == 0
|
20
|
+
cells << cell
|
21
|
+
parts << line_to_block(cell.text, width, text_to_options(cell))
|
22
|
+
end
|
23
|
+
|
24
|
+
# Make all the blocks have the same amount of lines
|
25
|
+
max_length = parts.map(&:size).max
|
26
|
+
column_widths.zip(parts).each do |width, lines|
|
27
|
+
lines << (' ' * width) while lines.size < max_length
|
28
|
+
end
|
29
|
+
|
30
|
+
# Add lines
|
31
|
+
parts.transpose.each do |line_parts|
|
32
|
+
cells.zip(line_parts).each_with_index do |(cell, part), i|
|
33
|
+
@buffer << ' ' if i > 0
|
34
|
+
font(text_to_options(cell)) do
|
35
|
+
@buffer << part
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
@last_added = :table
|
42
|
+
add_spacer
|
43
|
+
end
|
44
|
+
|
45
|
+
def _calculate_table_column_widths(table)
|
46
|
+
# Calculate the column widths
|
47
|
+
widths = table.get_column_widths
|
48
|
+
totals = [widths.map(&:first).sum, widths.map(&:second).sum, widths.map(&:third).sum]
|
49
|
+
columns = (table.columns - [:hide]).size
|
50
|
+
spacers = columns - 1
|
51
|
+
|
52
|
+
# Calculate the flex space
|
53
|
+
flex = @line_width - totals[0] - spacers
|
54
|
+
flex_columns = table.columns.count(:expand)
|
55
|
+
flex_indexes = table.columns.each_with_index.select { |c, i| c == :expand }.map(&:second)
|
56
|
+
flex_total_weight = widths.values_at(*flex_indexes).map(&:second).sum
|
57
|
+
fail ArgumentError, 'Table cannot fit' if flex < flex_columns
|
58
|
+
|
59
|
+
# Determine the final column width
|
60
|
+
final_widths = widths.map do |min, desired, max|
|
61
|
+
next min if min == max
|
62
|
+
next (flex * (desired / flex_total_weight - 0.001)).round
|
63
|
+
end
|
64
|
+
fail ArgumentError, 'Unable to calculate column widths' if final_widths.sum + spacers > @line_width
|
65
|
+
|
66
|
+
return final_widths
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'udrs/renderers/base'
|
2
|
+
|
3
|
+
require 'prawn'
|
4
|
+
require 'prawn/table'
|
5
|
+
require 'barby/barcode/qr_code'
|
6
|
+
require 'barby/outputter/prawn_outputter'
|
7
|
+
|
8
|
+
module UDRS
|
9
|
+
module Renderers
|
10
|
+
class PDFRenderer < Base
|
11
|
+
FORMAT_TIME = '%A %-d %B %Y %H:%M (%P)'
|
12
|
+
|
13
|
+
def render(container)
|
14
|
+
# Create the pdf
|
15
|
+
@pdf = Prawn::Document.new
|
16
|
+
|
17
|
+
# Allow bold fonts
|
18
|
+
@pdf.font_families.update(
|
19
|
+
'DejaVuSans' => {
|
20
|
+
normal: 'app/assets/DejaVuSans.ttf',
|
21
|
+
bold: 'app/assets/DejaVuSans-Bold.ttf',
|
22
|
+
},
|
23
|
+
)
|
24
|
+
@pdf.font('DejaVuSans', size: @pdf.font_size)
|
25
|
+
|
26
|
+
# Render the items
|
27
|
+
render_item(container)
|
28
|
+
|
29
|
+
# Render the pdf
|
30
|
+
return @pdf.render
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
SIZE_MAP = {
|
36
|
+
tiny: 9,
|
37
|
+
small: 11,
|
38
|
+
normal: 12,
|
39
|
+
medium: 14,
|
40
|
+
large: 16,
|
41
|
+
huge: 18,
|
42
|
+
}
|
43
|
+
|
44
|
+
def render_page_end(page_end)
|
45
|
+
@pdf.start_new_page
|
46
|
+
end
|
47
|
+
|
48
|
+
def render_spacer(spacer)
|
49
|
+
if spacer.amount > 0
|
50
|
+
@pdf.move_down(spacer.amount)
|
51
|
+
else
|
52
|
+
@pdf.move_up(-1 * spacer.amount)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def render_header(header)
|
57
|
+
case header.level
|
58
|
+
when 1
|
59
|
+
@pdf.move_down(15)
|
60
|
+
@pdf.font(@pdf.font.name, size: SIZE_MAP[:huge], style: :bold) do
|
61
|
+
@pdf.text(header.text)
|
62
|
+
end
|
63
|
+
|
64
|
+
when 2
|
65
|
+
@pdf.move_down(10)
|
66
|
+
@pdf.font(@pdf.font.name, size: SIZE_MAP[:large], style: :bold) do
|
67
|
+
@pdf.text(header.text)
|
68
|
+
end
|
69
|
+
|
70
|
+
when 3
|
71
|
+
@pdf.move_down(5)
|
72
|
+
@pdf.font(@pdf.font.name, size: SIZE_MAP[:medium], style: :bold) do
|
73
|
+
@pdf.text(header.text)
|
74
|
+
end
|
75
|
+
|
76
|
+
else
|
77
|
+
fail ArgumentError, "Invalid header level: #{header.level}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def render_text(item)
|
82
|
+
@pdf.font('DejaVuSans', style: _text_to_style(item), size: SIZE_MAP[item.size]) do
|
83
|
+
@pdf.text(item.text, align: item.alignment)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def render_t_text(item)
|
88
|
+
c = @pdf.cursor
|
89
|
+
title_width = @pdf.bounds.width / 4
|
90
|
+
@pdf.bounding_box([0, c], width: @pdf.bounds.width) do
|
91
|
+
title_box = @pdf.bounding_box([0, 0], width: title_width) do
|
92
|
+
@pdf.font('DejaVuSans', style: :bold) do
|
93
|
+
@pdf.text(item.title)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
content_box = @pdf.bounding_box(
|
97
|
+
[title_width, title_box.height],
|
98
|
+
width: @pdf.bounds.width - title_width,
|
99
|
+
) do
|
100
|
+
@pdf.text(item.body)
|
101
|
+
end
|
102
|
+
@pdf.move_cursor_to([title_box.bottom, content_box.bottom].max)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def render_logo(logo)
|
107
|
+
@pdf.image('app/assets/images/logo.png', position: logo.alignment, vposition: logo.valignment)
|
108
|
+
end
|
109
|
+
|
110
|
+
def render_code(code)
|
111
|
+
qrcode = Barby::QrCode.new(code.code)
|
112
|
+
outputter = Barby::PrawnOutputter.new(qrcode)
|
113
|
+
dim = 4
|
114
|
+
@pdf.move_down(outputter.full_height * dim)
|
115
|
+
outputter.annotate_pdf(@pdf, xdim: dim)
|
116
|
+
@pdf.move_up(outputter.full_height)
|
117
|
+
end
|
118
|
+
|
119
|
+
def render_table(table)
|
120
|
+
table_data = table.rows.map { |r| r.cells.map(&:text) }
|
121
|
+
@pdf.table(table_data) do |tbl|
|
122
|
+
# Lines between all cells
|
123
|
+
tbl.cells.borders = %i(bottom right)
|
124
|
+
tbl.rows(-1).borders = %i(right)
|
125
|
+
tbl.columns(-1).borders = %i(bottom)
|
126
|
+
tbl.rows(-1).columns(-1).borders = []
|
127
|
+
|
128
|
+
# Column sizes
|
129
|
+
table.columns.each_with_index do |width, ci|
|
130
|
+
next if width == :expand # Default, so do nothing
|
131
|
+
|
132
|
+
# For fit, calculate the needed width
|
133
|
+
if width == :fit
|
134
|
+
widths = table.rows.map do |row|
|
135
|
+
cell = row.cells[ci]
|
136
|
+
next @pdf.width_of(cell.text, style: _text_to_style(cell), size: SIZE_MAP[cell.size])
|
137
|
+
end
|
138
|
+
width = widths.max
|
139
|
+
end
|
140
|
+
|
141
|
+
pdf_cell = tbl.column(ci).first
|
142
|
+
pdf_cell.width = width + pdf_cell.padding_left + pdf_cell.padding_right
|
143
|
+
end
|
144
|
+
|
145
|
+
# Cell styles
|
146
|
+
table.rows.each_with_index do |row, ri|
|
147
|
+
row.cells.each_with_index do |cell, ci|
|
148
|
+
pdf_cell = tbl.rows(ri).columns(ci)
|
149
|
+
pdf_cell.align = cell.alignment
|
150
|
+
pdf_cell.font_style = _text_to_style(cell)
|
151
|
+
pdf_cell.font_size = SIZE_MAP[cell.size]
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def render_container(container)
|
158
|
+
render_items(container.items)
|
159
|
+
end
|
160
|
+
|
161
|
+
def render_footer(footer)
|
162
|
+
@pdf.bounding_box([0, 35], width: @pdf.bounds.width, height: 35) do
|
163
|
+
render_items(footer.items)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def render_raw(raw)
|
168
|
+
raw.block.call(@pdf)
|
169
|
+
end
|
170
|
+
|
171
|
+
def _text_to_style(text)
|
172
|
+
style = :normal
|
173
|
+
style = :bold if text.is_bold?
|
174
|
+
# style = :italic if text.is_italic?
|
175
|
+
# style = :underline if text.is_underline?
|
176
|
+
return style
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
data/lib/udrs/version.rb
ADDED
data/udrs.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'udrs/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'udrs'
|
8
|
+
spec.version = Udrs::VERSION
|
9
|
+
spec.authors = ['Michon van Dooren']
|
10
|
+
spec.email = ['michon1992@gmail.com']
|
11
|
+
|
12
|
+
spec.summary = %q{Simple templates to generate documents in various formats.}
|
13
|
+
spec.homepage = 'https://github.com/MaienM/UDRS'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = Dir.glob('lib/**/**/*') + %w(udrs.gemspec LICENSE.txt README.md)
|
17
|
+
spec.bindir = 'exe'
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_dependency 'attribute_predicates', '~> 0.2'
|
22
|
+
spec.add_dependency 'barby', '~> 0.6'
|
23
|
+
spec.add_dependency 'facets', '~> 3'
|
24
|
+
spec.add_dependency 'prawn', '~> 2'
|
25
|
+
spec.add_dependency 'prawn-table', '~> 0.2'
|
26
|
+
spec.add_dependency 'rqrcode', '~> 0.9'
|
27
|
+
spec.add_runtime_dependency 'rails', '~> 4'
|
28
|
+
spec.add_development_dependency 'bundler', '~> 1.10'
|
29
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,199 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: udrs
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michon van Dooren
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-05-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: attribute_predicates
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: barby
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.6'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: facets
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: prawn
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: prawn-table
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.2'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.2'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rqrcode
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.9'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.9'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rails
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '4'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '4'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: bundler
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '1.10'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '1.10'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rake
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '10.0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '10.0'
|
139
|
+
description:
|
140
|
+
email:
|
141
|
+
- michon1992@gmail.com
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- LICENSE.txt
|
147
|
+
- README.md
|
148
|
+
- lib/udrs.rb
|
149
|
+
- lib/udrs/components.rb
|
150
|
+
- lib/udrs/components/code.rb
|
151
|
+
- lib/udrs/components/container.rb
|
152
|
+
- lib/udrs/components/footer.rb
|
153
|
+
- lib/udrs/components/header.rb
|
154
|
+
- lib/udrs/components/logo.rb
|
155
|
+
- lib/udrs/components/page_end.rb
|
156
|
+
- lib/udrs/components/raw.rb
|
157
|
+
- lib/udrs/components/spacer.rb
|
158
|
+
- lib/udrs/components/t_text.rb
|
159
|
+
- lib/udrs/components/table.rb
|
160
|
+
- lib/udrs/components/text.rb
|
161
|
+
- lib/udrs/document.rb
|
162
|
+
- lib/udrs/engine.rb
|
163
|
+
- lib/udrs/engine/rails_helper.rb
|
164
|
+
- lib/udrs/engine/template_renderer.rb
|
165
|
+
- lib/udrs/renderers.rb
|
166
|
+
- lib/udrs/renderers/base.rb
|
167
|
+
- lib/udrs/renderers/escp_renderer.rb
|
168
|
+
- lib/udrs/renderers/escp_renderer/font.rb
|
169
|
+
- lib/udrs/renderers/escp_renderer/line.rb
|
170
|
+
- lib/udrs/renderers/escp_renderer/table.rb
|
171
|
+
- lib/udrs/renderers/pdf_renderer.rb
|
172
|
+
- lib/udrs/version.rb
|
173
|
+
- udrs.gemspec
|
174
|
+
homepage: https://github.com/MaienM/UDRS
|
175
|
+
licenses:
|
176
|
+
- MIT
|
177
|
+
metadata: {}
|
178
|
+
post_install_message:
|
179
|
+
rdoc_options: []
|
180
|
+
require_paths:
|
181
|
+
- lib
|
182
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
183
|
+
requirements:
|
184
|
+
- - ">="
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: '0'
|
187
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
188
|
+
requirements:
|
189
|
+
- - ">="
|
190
|
+
- !ruby/object:Gem::Version
|
191
|
+
version: '0'
|
192
|
+
requirements: []
|
193
|
+
rubyforge_project:
|
194
|
+
rubygems_version: 2.4.5.1
|
195
|
+
signing_key:
|
196
|
+
specification_version: 4
|
197
|
+
summary: Simple templates to generate documents in various formats.
|
198
|
+
test_files: []
|
199
|
+
has_rdoc:
|