30-33頁 第1章 計算とフォーマットにフェーズ分割「パイプラインによるループの置き換え(p.240)」「ファイル分離」「HTML版」
データ生成も含めて全て掲載します。
Swift版 main.swift
データ生成、結果表示付き。
import Foundation
makeData()
func statement(invoice:Invoice, plays:Dictionary<String, Play>) -> String {
return renderPlainText(data: createStatementData(invoice: invoice, plays: plays))
}
func renderPlainText(data:StatementData) -> String {
var result = "Statement for \(data.customer)\n"
for perf in data.performances {
result += " \(perf.play.name): " + usd(aNumber: perf.amount) + " (\(perf.performance.audience) seats)\n"
}
result += "Amount owed is " + usd(aNumber: data.totalAmount) + "\n"
result += "You earned \(data.totalVolumeCredits) credits\n"
return result
}
func htmlStatement(invoice:Invoice, plays:Dictionary<String, Play>) -> String {
renderHtml(data: createStatementData(invoice: invoice, plays: plays))
}
func renderHtml(data:StatementData) -> String {
var result = "<h1>Statement for \(data.customer)</h1>\n"
result += "<table>¥n"
result += "<tr><th>play</th><th>seats</th><th>cost</th></tr>\n"
for perf in data.performances {
result += " <tr><td>\(perf.play.name)</td><td>\(perf.performance.audience)</td>"
result += "<td></td>" + usd(aNumber: perf.amount) + "</td></tr>\n"
}
result += "</table>\n"
result += "<p>Amount owed is <em>" + usd(aNumber: data.totalAmount) + "</em></p>\n"
result += "<p>You earned <em>\(data.totalVolumeCredits)</em> credits</p>\n"
return result
}
let resultPlain = statement(invoice: invoices[0], plays: plays)
print("--- Plain Text ---")
print(resultPlain)
let resultHtml = htmlStatement(invoice: invoices[0], plays: plays)
print("--- HTML ---")
print(resultHtml)
Swift版 createStatementData.swift
import Foundation
struct PerormanceMapPlay {
let performance: Performance
let play: Play
var amount: Int = 0
var volumeCredits: Int = 0
}
struct StatementData {
let customer: String
let performances: [PerormanceMapPlay]
var totalAmount: Int = 0
var totalVolumeCredits: Int = 0
}
func playFor(aPerformance:Performance) -> Play {
return plays[aPerformance.playID]!
}
func volumeCreditsFor(aPerformance:Performance) -> Int {
var result = 0
result += max(aPerformance.audience - 30, 0)
if "comedy" == playFor(aPerformance: aPerformance).type {
result += Int(aPerformance.audience / 5)
}
return result
}
func usd(aNumber:Int) -> String {
let format = NumberFormatter()
format.numberStyle = .currency
format.locale = Locale(identifier: "en_US")
return format.string(from: NSNumber(value: aNumber / 100))!
}
func totalVolumeCredits(data:StatementData) -> Int {
return data.performances.reduce(0) { (num: Int, perf: PerormanceMapPlay) -> Int in
num + perf.volumeCredits
}
}
func totalAmount(data:StatementData) -> Int {
return data.performances.reduce(0) { (num: Int, perf: PerormanceMapPlay) -> Int in
num + perf.amount
}
}
func amountFor(aPerformance:PerormanceMapPlay) -> Int {
var result = 0
switch aPerformance.play.type {
case "tragedy":
result = 40000
if aPerformance.performance.audience > 30 {
result += 1000 * (aPerformance.performance.audience - 30)
}
case "comedy":
result = 30000
if aPerformance.performance.audience > 20 {
result += 10000 + 500 * (aPerformance.performance.audience - 20)
}
result += 300 * aPerformance.performance.audience
default:
print("error")
}
return result
}
func enrichPerfoemance(aPerformance:[Performance], plays:Dictionary<String, Play>) -> [PerormanceMapPlay] {
var result: [PerormanceMapPlay] = []
for perf in aPerformance {
var perormanceMapPlay = PerormanceMapPlay(performance: perf, play: playFor(aPerformance: perf))
perormanceMapPlay.amount = amountFor(aPerformance: perormanceMapPlay)
perormanceMapPlay.volumeCredits = volumeCreditsFor(aPerformance: perf)
result.append(perormanceMapPlay)
}
return result
}
func createStatementData(invoice:Invoice, plays:Dictionary<String, Play>) -> StatementData {
var result = StatementData(customer: invoice.customer, performances: enrichPerfoemance(aPerformance: invoice.performances, plays: plays))
result.totalAmount = totalAmount(data: result)
result.totalVolumeCredits = totalVolumeCredits(data: result)
return result
}
Swift版 data.swift
import Foundation
let json_plays = """
{
"hamlet": {"name": "Hamlet", "type": "tragedy"},
"aslike": {"name": "As You Like It", "type": "comedy"},
"othello": {"name": "Othello", "type": "tragedy"}
}
"""
let json_invoices = """
[
{
"customer": "BigCo",
"performances": [
{
"playID": "hamlet",
"audience": 55
},
{
"playID": "aslike",
"audience": 35
},
{
"playID": "othello",
"audience": 40
}
]
}
]
"""
struct Play: Codable {
let name: String
let type: String
}
struct Plays: Codable {
let hamlet: Play
let aslike: Play
let othello: Play
}
struct Performance: Codable {
let playID: String
let audience: Int
}
struct Invoice: Codable {
let customer: String
let performances:[Performance]
}
let json_plays_data: Data = json_plays.data(using: String.Encoding.utf8)!
let json_invoices_data:Data = json_invoices.data(using: String.Encoding.utf8)!
var plays:Dictionary<String, Play> = [:]
var invoices:[Invoice] = []
func makeData() {
let decoder: JSONDecoder = JSONDecoder()
do {
let json: Plays = try decoder.decode(Plays.self, from: json_plays_data)
plays["hamlet"] = json.hamlet
plays["aslike"] = json.aslike
plays["othello"] = json.othello
} catch {
print("error:", error.localizedDescription)
}
do {
let json = try decoder.decode([Invoice].self, from: json_invoices_data)
invoices = json
} catch {
print("error:", error.localizedDescription)
}
}