prep 0.2.2
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.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +30 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +24 -0
- data/Rakefile +51 -0
- data/VERSION +1 -0
- data/bin/prep-helper +48 -0
- data/bin/prep-test +51 -0
- data/examples/generate_group_sample.rb +4 -0
- data/examples/generate_sample.rb +4 -0
- data/examples/generate_sample2.rb +19 -0
- data/examples/generate_sample3.rb +20 -0
- data/examples/generate_sample4.rb +31 -0
- data/examples/generate_sample5.rb +74 -0
- data/examples/generate_sample6.rb +40 -0
- data/examples/generate_sample_dataset.rb +9 -0
- data/examples/group_sample.yml +121 -0
- data/examples/sample.yml +90 -0
- data/examples/sample2.yml +164 -0
- data/examples/sample3.yml +206 -0
- data/examples/sample5.yml +116 -0
- data/examples/sample6.yml +127 -0
- data/lib/core/color.rb +47 -0
- data/lib/core/drawable.rb +163 -0
- data/lib/core/group.rb +193 -0
- data/lib/core/label.rb +125 -0
- data/lib/core/line.rb +95 -0
- data/lib/core/loop.rb +584 -0
- data/lib/core/page.rb +87 -0
- data/lib/core/page_ext.rb +14 -0
- data/lib/core/point.rb +26 -0
- data/lib/core/prep.rb +351 -0
- data/lib/core/rectangle.rb +137 -0
- data/lib/core/region.rb +54 -0
- data/lib/mm2pixcel.rb +5 -0
- data/lib/prep.rb +175 -0
- data/prep.gemspec +108 -0
- data/spec/component_spec.rb +5 -0
- data/spec/prep_spec.rb +7 -0
- data/spec/spec_helper.rb +12 -0
- metadata +197 -0
data/lib/core/page.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
# Page クラスのソースファイル
|
2
|
+
# Author:: maki-tetsu
|
3
|
+
# Date:: 2011/03/11
|
4
|
+
# Copyright:: Copyright (c) 2011 maki-tetsu
|
5
|
+
|
6
|
+
require "rubygems"
|
7
|
+
gem "hpdf"
|
8
|
+
require "hpdf"
|
9
|
+
|
10
|
+
module PREP # nodoc
|
11
|
+
module Core # nodoc
|
12
|
+
# ページ設定を保持するクラス
|
13
|
+
class Page
|
14
|
+
# ページサイズの設定種別
|
15
|
+
SIZES = {
|
16
|
+
:a4 => HPDFDoc::HPDF_PAGE_SIZE_A4, # A4
|
17
|
+
:a3 => HPDFDoc::HPDF_PAGE_SIZE_A3, # A3
|
18
|
+
}
|
19
|
+
|
20
|
+
# ページ方向の設定種別
|
21
|
+
ORIENTATIONS = {
|
22
|
+
:portrait => HPDFDoc::HPDF_PAGE_PORTRAIT, # 縦
|
23
|
+
:landscape => HPDFDoc::HPDF_PAGE_LANDSCAPE, # 横
|
24
|
+
}
|
25
|
+
|
26
|
+
attr_reader :size, :orientation, :margin, :header_height, :footer_height
|
27
|
+
|
28
|
+
# 初期化
|
29
|
+
def initialize
|
30
|
+
@size = SIZES[:a4]
|
31
|
+
@orientation = ORIENTATIONS[:portrate]
|
32
|
+
@margin = {
|
33
|
+
:top => 0,
|
34
|
+
:left => 0,
|
35
|
+
:bottom => 0,
|
36
|
+
:right => 0
|
37
|
+
}
|
38
|
+
@header_height = 0
|
39
|
+
@footer_height = 0
|
40
|
+
end
|
41
|
+
|
42
|
+
def size=(size)
|
43
|
+
if SIZES.values.include?(size)
|
44
|
+
@size = size
|
45
|
+
else
|
46
|
+
raise "Unknown PAGE SIZE."
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def orientation=(orientation)
|
51
|
+
if ORIENTATIONS.values.include?(orientation)
|
52
|
+
@orientation = orientation
|
53
|
+
else
|
54
|
+
raise "Unknown PAGE ORIENTATION."
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def margin=(values)
|
59
|
+
sym_key_values = values.keys.inject({ }) do |hash, key|
|
60
|
+
hash[key.to_sym] = values[key]
|
61
|
+
next hash
|
62
|
+
end
|
63
|
+
if (sym_key_values.keys - @margin.keys).length.zero?
|
64
|
+
@margin.merge!(sym_key_values)
|
65
|
+
else
|
66
|
+
raise "Unknown margin keys (#{(sym_key_values.keys - @margin.keys).join(",")})."
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def header_height=(height)
|
71
|
+
if height >= 0
|
72
|
+
@header_height = height
|
73
|
+
else
|
74
|
+
raise "Invalid header height(#{height})."
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def footer_height=(height)
|
79
|
+
if height >= 0
|
80
|
+
@footer_height = height
|
81
|
+
else
|
82
|
+
raise "Invalid footer height(#{height})."
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/lib/core/point.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# Point クラスのソースファイル
|
2
|
+
# Author:: maki-tetsu
|
3
|
+
# Date:: 2011/03/11
|
4
|
+
# Copyright:: Copyright (c) 2011 maki-tetsu
|
5
|
+
|
6
|
+
module PREP # nodoc
|
7
|
+
module Core # nodoc
|
8
|
+
class Point
|
9
|
+
attr_reader :x, :y
|
10
|
+
|
11
|
+
def initialize(x, y)
|
12
|
+
self.x, self.y = x, y
|
13
|
+
end
|
14
|
+
|
15
|
+
def x=(v)
|
16
|
+
raise "x cannot be nil." if v.nil?
|
17
|
+
@x = v
|
18
|
+
end
|
19
|
+
|
20
|
+
def y=(v)
|
21
|
+
raise "y cannot be nil." if v.nil?
|
22
|
+
@y = v
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/core/prep.rb
ADDED
@@ -0,0 +1,351 @@
|
|
1
|
+
# Prep クラスのソースファイル
|
2
|
+
# Author:: maki-tetsu
|
3
|
+
# Date:: 2011/03/11
|
4
|
+
# Copyright:: Copyright (c) 2011 maki-tetsu
|
5
|
+
|
6
|
+
require "yaml"
|
7
|
+
require "rubygems"
|
8
|
+
gem "hpdf"
|
9
|
+
require "hpdf"
|
10
|
+
|
11
|
+
require File.join(File.dirname(__FILE__), "label")
|
12
|
+
require File.join(File.dirname(__FILE__), "line")
|
13
|
+
require File.join(File.dirname(__FILE__), "rectangle")
|
14
|
+
require File.join(File.dirname(__FILE__), "group")
|
15
|
+
require File.join(File.dirname(__FILE__), "region")
|
16
|
+
require File.join(File.dirname(__FILE__), "page")
|
17
|
+
require File.join(File.dirname(__FILE__), "page_ext")
|
18
|
+
require File.join(File.dirname(__FILE__), "..", "mm2pixcel")
|
19
|
+
|
20
|
+
module PREP
|
21
|
+
module Core
|
22
|
+
# PREP の中心クラス
|
23
|
+
class Prep
|
24
|
+
attr_reader :pdf, :pages, :page_pos_x, :page_pos_y, :values
|
25
|
+
|
26
|
+
# 初期化
|
27
|
+
#
|
28
|
+
# 設定ファイルのパスが与えられれば初期化
|
29
|
+
# 無ければブランクの設定をロード
|
30
|
+
def initialize(configuration_file_path = nil)
|
31
|
+
if configuration_file_path
|
32
|
+
if File.exists?(configuration_file_path)
|
33
|
+
load_configuration(configuration_file_path)
|
34
|
+
else
|
35
|
+
raise "File not found \"#{configuration_file_path}\"."
|
36
|
+
end
|
37
|
+
else
|
38
|
+
init_configuration
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# データセット雛形を生成して返却
|
43
|
+
def generate_sample_dataset
|
44
|
+
# ヘッダのデータセット生成
|
45
|
+
dataset = { }
|
46
|
+
if @content.has_identifier?(:header)
|
47
|
+
dataset[:header] = @content[:header].generate_sample_dataset(self)
|
48
|
+
end
|
49
|
+
dataset[:content] = @content[:content].generate_sample_dataset(self)
|
50
|
+
if @content.has_identifier?(:footer)
|
51
|
+
dataset[:footer] = @content[:footer].generate_sample_dataset(self)
|
52
|
+
end
|
53
|
+
|
54
|
+
return dataset
|
55
|
+
end
|
56
|
+
|
57
|
+
# 帳票の生成
|
58
|
+
def generate(output_file_path, values = { })
|
59
|
+
# 再描画用に初期値を保持
|
60
|
+
@values = values.dup
|
61
|
+
@pdf = HPDFDoc.new
|
62
|
+
# 日本語対応
|
63
|
+
@pdf.use_jp_fonts
|
64
|
+
@pdf.use_jp_encodings
|
65
|
+
# ページの初期化
|
66
|
+
initialize_pages
|
67
|
+
|
68
|
+
draw_contents(values)
|
69
|
+
draw_headers(values)
|
70
|
+
draw_footers(values)
|
71
|
+
|
72
|
+
# 指定されたファイルへの書込
|
73
|
+
@pdf.save_to_file(output_file_path)
|
74
|
+
rescue => e
|
75
|
+
@pdf.save_to_file(output_file_path) if ENV["DEBUG"]
|
76
|
+
puts "Error occured!!\n#{e}"
|
77
|
+
raise e
|
78
|
+
end
|
79
|
+
|
80
|
+
# ページの初期化
|
81
|
+
def initialize_pages
|
82
|
+
# 一次元配列
|
83
|
+
@pages = []
|
84
|
+
# 二次元配列
|
85
|
+
@flat_pages = []
|
86
|
+
# ページの作成
|
87
|
+
page = generate_page
|
88
|
+
# 1ページ目の登録
|
89
|
+
@pages << page
|
90
|
+
@flat_pages = [[page]] # [0][0] 位置への追加
|
91
|
+
# 現在のページの位置情報を初期化
|
92
|
+
@page_pos_x, @page_pos_y = 0, 0
|
93
|
+
|
94
|
+
return page
|
95
|
+
end
|
96
|
+
|
97
|
+
# コンテンツの埋め込み
|
98
|
+
def draw_contents(values)
|
99
|
+
content = @content[:content]
|
100
|
+
|
101
|
+
# 描画領域を含めて描画開始
|
102
|
+
content.draw(self, page_content_region, values[:content])
|
103
|
+
end
|
104
|
+
|
105
|
+
# ヘッダの埋め込み
|
106
|
+
def draw_headers(values)
|
107
|
+
return unless @content.has_identifier?(:header)
|
108
|
+
|
109
|
+
header = @content[:header]
|
110
|
+
|
111
|
+
# 全てのページに対してインデックスを切り替えながら実行
|
112
|
+
@flat_pages.each_with_index do |row_pages, y|
|
113
|
+
row_pages.each_with_index do |page, x|
|
114
|
+
self.current_page = { :x => x, :y => y }
|
115
|
+
header.draw(self, page_header_region, values[:header])
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# フッタの埋め込み
|
121
|
+
def draw_footers(values)
|
122
|
+
return unless @content.has_identifier?(:footer)
|
123
|
+
|
124
|
+
footer = @content[:footer]
|
125
|
+
|
126
|
+
# 全てのページに対してインデックスを切り替えながら実行
|
127
|
+
@flat_pages.each_with_index do |row_pages, y|
|
128
|
+
row_pages.each_with_index do |page, x|
|
129
|
+
self.current_page = { :x => x, :y => y }
|
130
|
+
footer.draw(self, page_footer_region, values[:footer])
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# ページの移動および追加
|
136
|
+
#
|
137
|
+
# 指定された位置への移動に際してページが存在しなければページを追加
|
138
|
+
def move_page_to(x, y)
|
139
|
+
puts "[#{@page_pos_x}:#{@page_pos_y}] => [#{@page_pos_x + x}:#{@page_pos_y + y}]" if ENV["DEBUG"]
|
140
|
+
@page_pos_x, @page_pos_y = @page_pos_x + x, @page_pos_y + y
|
141
|
+
|
142
|
+
@flat_pages[@page_pos_y] ||= []
|
143
|
+
if @flat_pages[@page_pos_y][@page_pos_x].nil?
|
144
|
+
@flat_pages[@page_pos_y][@page_pos_x] = (page = generate_page)
|
145
|
+
@pages << page
|
146
|
+
end
|
147
|
+
|
148
|
+
print_flat_pages if ENV["DEBUG"]
|
149
|
+
|
150
|
+
return @flat_pages[@page_pos_y][@page_pos_x]
|
151
|
+
end
|
152
|
+
|
153
|
+
# 移動先のページが存在するかどうかをチェック
|
154
|
+
def exists_move_to_page?(x, y)
|
155
|
+
x += @page_pos_x
|
156
|
+
y += @page_pos_y
|
157
|
+
|
158
|
+
return exists_and_drawed_page?(x, y)
|
159
|
+
end
|
160
|
+
|
161
|
+
# 指定されたページが存在するかどうかをチェック
|
162
|
+
def exists_page?(x, y)
|
163
|
+
if @flat_pages[y].nil?
|
164
|
+
return false
|
165
|
+
elsif @flat_pages[y][x].nil?
|
166
|
+
return false
|
167
|
+
else
|
168
|
+
return true
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# 指定されたページが存在し描画済みであるかどうかをチェック
|
173
|
+
def exists_and_drawed_page?(x, y)
|
174
|
+
if exists_page?(x, y)
|
175
|
+
return @flat_pages[y][x].drawed?
|
176
|
+
else
|
177
|
+
return false
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# ページオブジェクトの作成とページ設定
|
182
|
+
def generate_page
|
183
|
+
page = @pdf.add_page
|
184
|
+
page.set_size(@page_config.size, @page_config.orientation)
|
185
|
+
|
186
|
+
return page
|
187
|
+
end
|
188
|
+
|
189
|
+
# 現在の総ページ数を返却
|
190
|
+
def total_pages
|
191
|
+
return @pages.size
|
192
|
+
end
|
193
|
+
|
194
|
+
# 現在描画中のページインスタンスを返却
|
195
|
+
def current_page
|
196
|
+
return @flat_pages[@page_pos_y][@page_pos_x]
|
197
|
+
end
|
198
|
+
|
199
|
+
# 現在の通しページ番号を返却
|
200
|
+
def current_page_number
|
201
|
+
@pages.each_with_index do |page, index|
|
202
|
+
if page === current_page
|
203
|
+
return index + 1
|
204
|
+
end
|
205
|
+
end
|
206
|
+
raise "Unknown Page instance \"#{page}\"."
|
207
|
+
end
|
208
|
+
|
209
|
+
# 現在のページを強制的に変更
|
210
|
+
#
|
211
|
+
# 存在しないページへの移動は不可(例外)
|
212
|
+
# 引数の形式はハッシュ: Ex.) { :x => 0, :y => 0 }
|
213
|
+
def current_page=(pos)
|
214
|
+
if exists_page?(pos[:x], pos[:y])
|
215
|
+
puts "[#{@page_pos_x}:#{@page_pos_y}] => [#{pos[:x]}:#{pos[:y]}]" if ENV["DEBUG"]
|
216
|
+
@page_pos_x, @page_pos_y = pos[:x], pos[:y]
|
217
|
+
print_flat_pages if ENV["DEBUG"]
|
218
|
+
return current_page
|
219
|
+
else
|
220
|
+
print_flat_pages if ENV["DEBUG"]
|
221
|
+
raise "Unknown page index [#{pos[:x]},#{pos[:y]}]."
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
# ページ構成を模式印字するデバッグ用メソッド
|
226
|
+
def print_flat_pages
|
227
|
+
@flat_pages.each_with_index do |flat_page, y|
|
228
|
+
flat_page.each_with_index do |one_page, x|
|
229
|
+
char = one_page.nil? ? "?" : "."
|
230
|
+
if x == page_pos_x && y == page_pos_y
|
231
|
+
char = '!'
|
232
|
+
end
|
233
|
+
STDERR.write("[#{char}]")
|
234
|
+
end
|
235
|
+
STDERR.write("\n")
|
236
|
+
end
|
237
|
+
gets if ENV["DEBUG"]
|
238
|
+
end
|
239
|
+
|
240
|
+
# コンテンツ描画領域の取得
|
241
|
+
def page_content_region
|
242
|
+
# 全体の描画領域を取得
|
243
|
+
width = current_page.get_width
|
244
|
+
height = current_page.get_height
|
245
|
+
x = 0
|
246
|
+
y = 0
|
247
|
+
# マージンを含める
|
248
|
+
x += @page_config.margin[:left]
|
249
|
+
width -= (@page_config.margin[:left] + @page_config.margin[:right])
|
250
|
+
y += @page_config.margin[:top]
|
251
|
+
height -= (@page_config.margin[:top] + @page_config.margin[:bottom])
|
252
|
+
# ヘッダ、および、フッタ領域を含める
|
253
|
+
y += @page_config.header_height
|
254
|
+
height -= (@page_config.header_height + @page_config.footer_height)
|
255
|
+
|
256
|
+
return Region.new(x, y, width, height)
|
257
|
+
end
|
258
|
+
|
259
|
+
# ヘッダ領域の取得
|
260
|
+
def page_header_region
|
261
|
+
# 全体の描画領域を取得
|
262
|
+
width = current_page.get_width
|
263
|
+
height = current_page.get_height
|
264
|
+
x = 0
|
265
|
+
y = 0
|
266
|
+
# マージンを含める
|
267
|
+
x += @page_config.margin[:left]
|
268
|
+
width -= (@page_config.margin[:left] + @page_config.margin[:right])
|
269
|
+
y += @page_config.margin[:top]
|
270
|
+
# 高さをヘッダ領域に変更
|
271
|
+
height = @page_config.header_height
|
272
|
+
|
273
|
+
return Region.new(x, y, width, height)
|
274
|
+
end
|
275
|
+
|
276
|
+
# フッタ領域の取得
|
277
|
+
def page_footer_region
|
278
|
+
# 全体の描画領域を取得
|
279
|
+
width = current_page.get_width
|
280
|
+
height = current_page.get_height
|
281
|
+
x = 0
|
282
|
+
y = current_page.get_height
|
283
|
+
# マージンを含める
|
284
|
+
x += @page_config.margin[:left]
|
285
|
+
width -= (@page_config.margin[:left] + @page_config.margin[:right])
|
286
|
+
# 高さをフッタ領域に変更
|
287
|
+
height = @page_config.footer_height
|
288
|
+
# フッタの開始 Y 座標を計算
|
289
|
+
y -= (@page_config.margin[:bottom] + height)
|
290
|
+
|
291
|
+
return Region.new(x, y, width, height)
|
292
|
+
end
|
293
|
+
|
294
|
+
# 設定の初期化
|
295
|
+
def init_configuration
|
296
|
+
raise "Need configuration file!"
|
297
|
+
end
|
298
|
+
|
299
|
+
# 設定ファイルのロード
|
300
|
+
def load_configuration(configuration_file_path)
|
301
|
+
# YAML からハッシュ形式に変換
|
302
|
+
config_values = YAML.load_file(configuration_file_path)
|
303
|
+
|
304
|
+
# ページ設定情報を取り込み
|
305
|
+
@page_config = Page.new
|
306
|
+
if config_values["page"]
|
307
|
+
values = config_values["page"]
|
308
|
+
if !values["size"].nil? && values["size"] != ""
|
309
|
+
@page_config.size = Page::SIZES[values["size"].to_sym]
|
310
|
+
end
|
311
|
+
if !values["orientation"].nil? && values["orientation"] != ""
|
312
|
+
@page_config.orientation = Page::ORIENTATIONS[values["orientation"].to_sym]
|
313
|
+
end
|
314
|
+
if !values["margin"].nil?
|
315
|
+
margin_values = values["margin"].keys.inject({ }) do |hash, key|
|
316
|
+
hash[key.to_sym] = values["margin"][key].mm2pixcel
|
317
|
+
next hash
|
318
|
+
end
|
319
|
+
@page_config.margin = margin_values
|
320
|
+
end
|
321
|
+
if !values["header_height"].nil?
|
322
|
+
@page_config.header_height = values["header_height"].mm2pixcel
|
323
|
+
end
|
324
|
+
if !values["footer_height"].nil?
|
325
|
+
@page_config.footer_height = values["footer_height"].mm2pixcel
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
# コンテンツ定義情報を読み込む
|
330
|
+
# page 以外について読み込みを実施
|
331
|
+
@content = Group.new
|
332
|
+
config_values.keys.each do |identifier|
|
333
|
+
unless identifier == "page"
|
334
|
+
@content.add_drawable(identifier, config_values[identifier], true)
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
# 指定されたグループ識別子を検索して返却
|
340
|
+
# 存在しない場合は例外発生
|
341
|
+
def group(group_identifiy)
|
342
|
+
return @content[group_identifiy]
|
343
|
+
end
|
344
|
+
|
345
|
+
# 指定されたグループ識別子の存在確認
|
346
|
+
def has_group?(group_identifiy)
|
347
|
+
return @content.drawables.has_key?(group_identifiy.to_sym)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|