Slide 1

Slide 1 text

後⽅互換の保ち⽅ 松江Ruby会議09

Slide 2

Slide 2 text

⽇⾼ 克也 @hidakatsuya Misoca松江オフィス勤務 サーバサイド⽅⾯(主にRuby)
 Thinreports 開発者

Slide 3

Slide 3 text

Thinreports • Ruby向けのPDF⽣成ツール • OSS • Thinreports Editor - レイアウトを作成するデスクトップアプリ • Thinreports Generator for Ruby - レイアウトからPDFを作る gem

Slide 4

Slide 4 text

hello_world.tlf require 'thinreports' report = Thinreports::Report.new layout: ‘hello_world.tlf' report.start_new_page do |page| page.item(:world).value = 'World' end report.generate filename: ‘hello_world.pdf’ PDF

Slide 5

Slide 5 text

History • 2010年 0.6.0 プレビュー版リリース • 2011年 0.7.0 最初の安定版 • 2012年 Fukuoka Ruby Award 2012 で⼤賞受賞 • 2015年 0.8.0 リリース • 2015年 Thinreports for PHP がリリース • 2016年 0.9.0 リリース - レイアウトファイル (*.tlf) の仕様を⼤幅に変更 • 2017年 0.10.0 リリース

Slide 6

Slide 6 text

For PHP, Java, Go • https://github.com/thinreports-php/thinreports-php • https://bitbucket.org/symfo/thinreports-java • https://github.com/naofum/thinreports-java • https://github.com/renatosuero/thinreports-go

Slide 7

Slide 7 text

0.8 to 0.9 • レイアウトファイル (*.tlf) の内部構造を⼤幅に変更 • 互換性を壊す変更 • このときにどう対応したか • 以降、古い仕様を 0.8 ver、新しい仕様を 0.9 ver と呼称

Slide 8

Slide 8 text

0.8 ver tlf 1: { 2: "version": "0.8.2", 3: "config": { 4: "title": "Report Title", 5: "page": { 6: "paper-type": "A4", 7: "orientation": "landscape", 8: "margin-top": 0.0, 9: "margin-bottom": 0.0, 10: "margin-left": 0.0, 11: "margin-right": 0.0, 12: } 13: }, 14: "svg": "" 15: }

Slide 9

Slide 9 text

Ploblems for 0.8 ver • 変更箇所の Diff が全くわからない • Editor の実装に強く依存していて、仕様変更が困難 • 構造や属性の仕様がわかり⾟いし、扱いにくい - サードパーティにも広がらない

Slide 10

Slide 10 text

0.9 version • すべてをJSONで表現 • Editor の依存を排除 • Diff も⼀⽬瞭然 • ⼈間が読める • その後の開発が断然や りやすくなった { "version": "0.10.0", "items": [ { "type": "text", "display": true, "x": 210.6, "y": 55, "width": 174, "height": 48, "style": { "font-family": ["IPAGothic"], "font-size": 24, "color": "#000000", "text-align": "center", "vertical-align": "middle", "font-style": [] }, "texts": ["ݟੵॻ"] }, { "id": "recipient_name", "type": "text-block", "display": true, :

Slide 11

Slide 11 text

⽅針: 後⽅互換を保つ • 0.8 ver の tlf は Generator v0.9 でもそのまま利⽤できる • 0.8 ver の tlf は Editor v0.9 でも編集でき保存できる - 保存すると 0.9 ver の tlf になる

Slide 12

Slide 12 text

Generator v0.9 • 0.9 ver の tlf で PDF ⽣成できるように書き換える • tlf が 0.8 ver の場合は 0.9 ver に変換してから扱う - 0.8 ver to 0.9 ver にコンバートするクラスを追加

Slide 13

Slide 13 text

Thinreports::Layout::
 LegacySchema 1: def initialize(legacy_schema) 2: @legacy_schema = legacy_schema 3: : 4: end 5: 6: def upgrade 7: config = legacy_schema['config'] 8: page_config = config[‘page'] 9: 10: { 11: 'version' => legacy_schema['version'], 12: 'title' => legacy_schema['config']['title'], 13: 'report' => { 14: 'paper-type' => page_config['paper-type'], 15: 'width' => page_config['width'].to_f, 16: 'height' => page_config['height'].to_f, 17: : 18: }, 19: 'items' => item_schemas 20: } 21: end
 22: 23: private 24: :

Slide 14

Slide 14 text

Thinreports::Layout::Format 1: def self.build(filename) 2: schema = JSON.parse(read_file(filename)) 3: version = Layout::Version.new(schema['version']) 4: 5: unless version.compatible? 6: raise Errors::IncompatibleLayoutFormat.new( 7: filename, schema['version'], 8: Layout::Version.compatible_rules.join(' and ') 9: ) 10: end 11: 12: if version.legacy? 13: warn ‘[DEPRECATION] ...’ 14: schema = Layout::LegacySchema.new(schema).upgrade 15: end 16: 17: new schema #=> Thinreports::Layout::Format 18: end

Slide 15

Slide 15 text

Design • 0.8 ver に関する知識と責務を集約 • 0.8 ver の tlf に関するコードを排除 - 条件分岐は最⼩限にしたい • 考えることを増やさない - 以降の実装がやりやすい • テスト書きやすい

Slide 16

Slide 16 text

thinreports-cli gem • Editor 0.9 で⼀個ずつ開いて保存して変換→⾟いとの声 • 0.8 ver の tlf を 0.9 ver に変換できるコマンドを作った $ thinreports upgrade /path/to/0.8.tlf /path/to/0.9.tlf

Slide 17

Slide 17 text

Reuse 1: module Thinreports 2: module Cli 3: module Commands 4: class Upgrade 5: def initialize(source_path, destination_path) 6: @source_path = Pathname.new(source_path) 7: @destination_path = Pathname.new(destination_path) 8: end 9: 10: def call 11: source_schema = load_source_schema 12: destination_path.write(upgrade_schema(source_schema), encoding: 'UTF-8') 13: end 14: 15: private 16: 17: attr_reader :source_path, :destination_path 18: 19: def upgrade_schema(source_schema) 20: upgraded_schema = Thinreports::Layout::LegacySchema.new(source_schema).upgrade 21: JSON.pretty_generate(upgraded_schema) 22: end 23: :

Slide 18

Slide 18 text

Future of Thinreports • Custom Font (WIP) - 任意のフォントが使えるようになる - だいたいできてる - https://github.com/thinreports/thinreports/issues/5 • Section Report (WIP) - 新しいレポート形式 - より柔軟に動的なレイアウトが作れるようになる - https://github.com/thinreports/thinreports/issues/7

Slide 19

Slide 19 text

end