prep 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|