pdf 0.1.0 → 0.1.1

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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/execution/00-overview.md +121 -0
  3. data/.claude/execution/01-core.md +324 -0
  4. data/.claude/execution/02-renderer.md +237 -0
  5. data/.claude/execution/03-components.md +551 -0
  6. data/.claude/execution/04-builders.md +322 -0
  7. data/.claude/execution/05-view-layout.md +362 -0
  8. data/.claude/execution/06-evaluators.md +494 -0
  9. data/.claude/execution/07-entry-extensibility.md +435 -0
  10. data/.claude/execution/08-integration-tests.md +978 -0
  11. data/Rakefile +7 -3
  12. data/examples/01_basic_invoice.rb +139 -0
  13. data/examples/02_report_with_layout.rb +266 -0
  14. data/examples/03_inherited_views.rb +318 -0
  15. data/examples/04_conditional_content.rb +421 -0
  16. data/examples/05_custom_components.rb +442 -0
  17. data/examples/README.md +123 -0
  18. data/lib/pdf/blueprint.rb +50 -0
  19. data/lib/pdf/builders/content_builder.rb +96 -0
  20. data/lib/pdf/builders/footer_builder.rb +24 -0
  21. data/lib/pdf/builders/header_builder.rb +31 -0
  22. data/lib/pdf/component.rb +43 -0
  23. data/lib/pdf/components/alert.rb +42 -0
  24. data/lib/pdf/components/context.rb +16 -0
  25. data/lib/pdf/components/date.rb +28 -0
  26. data/lib/pdf/components/heading.rb +12 -0
  27. data/lib/pdf/components/hr.rb +12 -0
  28. data/lib/pdf/components/logo.rb +15 -0
  29. data/lib/pdf/components/paragraph.rb +12 -0
  30. data/lib/pdf/components/qr_code.rb +38 -0
  31. data/lib/pdf/components/spacer.rb +11 -0
  32. data/lib/pdf/components/span.rb +12 -0
  33. data/lib/pdf/components/subtitle.rb +12 -0
  34. data/lib/pdf/components/table.rb +48 -0
  35. data/lib/pdf/components/title.rb +12 -0
  36. data/lib/pdf/content_evaluator.rb +218 -0
  37. data/lib/pdf/dynamic_components.rb +17 -0
  38. data/lib/pdf/footer_evaluator.rb +66 -0
  39. data/lib/pdf/header_evaluator.rb +56 -0
  40. data/lib/pdf/layout.rb +61 -0
  41. data/lib/pdf/renderer.rb +153 -0
  42. data/lib/pdf/resolver.rb +36 -0
  43. data/lib/pdf/version.rb +1 -1
  44. data/lib/pdf/view.rb +113 -0
  45. data/lib/pdf.rb +74 -1
  46. metadata +127 -2
@@ -0,0 +1,318 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Example 03: View Inheritance
5
+ # Run: ruby examples/03_inherited_views.rb
6
+ #
7
+ # Demonstrates:
8
+ # - Base view with shared elements
9
+ # - Child views that extend parent
10
+ # - Multi-level inheritance
11
+ # - Layout inheritance
12
+ # - Method overriding in child views
13
+ # - Shared and specialized sections
14
+
15
+ require_relative "../lib/pdf"
16
+
17
+ # --- Shared Layout ---
18
+
19
+ class CorporateLayout < Pdf::Layout
20
+ header do
21
+ context :document_header, label: "DOCUMENT"
22
+ end
23
+
24
+ footer do
25
+ text :company_footer, size: 7
26
+ page_number position: :right
27
+ end
28
+
29
+ margins top: 85, bottom: 65
30
+ end
31
+
32
+ # --- Base Document (Level 1) ---
33
+
34
+ class BaseDocument < Pdf::View
35
+ layout CorporateLayout
36
+
37
+ # All documents start with this
38
+ title :document_title, size: 20
39
+ date :document_date
40
+ hr
41
+ spacer amount: 10
42
+
43
+ # All documents end with this
44
+ def document_header
45
+ [
46
+ "Acme Corporation",
47
+ "Document: #{data[:doc_type] || 'General'}",
48
+ "ID: #{data[:doc_id] || 'N/A'}"
49
+ ]
50
+ end
51
+
52
+ def company_footer
53
+ "Acme Corporation | Confidential | #{Date.today.year}"
54
+ end
55
+
56
+ def document_title
57
+ data[:title] || "Untitled Document"
58
+ end
59
+
60
+ def document_date
61
+ data[:date] || Date.today
62
+ end
63
+ end
64
+
65
+ # --- Report Base (Level 2) - Extends BaseDocument ---
66
+
67
+ class BaseReport < BaseDocument
68
+ # Inherits: title, date, hr, spacer from BaseDocument
69
+
70
+ # Reports add an executive summary
71
+ alert :summary_alert
72
+
73
+ section "Overview" do
74
+ paragraph :overview_text
75
+ end
76
+
77
+ def summary_alert
78
+ {
79
+ title: "Summary",
80
+ description: data[:summary] || "No summary provided.",
81
+ color: "blue"
82
+ }
83
+ end
84
+
85
+ def overview_text
86
+ data[:overview] || "Overview not available."
87
+ end
88
+ end
89
+
90
+ # --- Sales Report (Level 3) - Extends BaseReport ---
91
+
92
+ class SalesReport < BaseReport
93
+ # Inherits: title, date, hr, spacer, summary_alert, overview section
94
+
95
+ section "Sales Performance" do
96
+ table :sales_data, columns: [
97
+ { key: :product, label: "Product" },
98
+ { key: :units, label: "Units Sold" },
99
+ { key: :revenue, label: "Revenue" },
100
+ { key: :margin, label: "Margin %" }
101
+ ]
102
+ end
103
+
104
+ section "Top Performers" do
105
+ each(:top_sellers) do |seller|
106
+ heading seller[:name], size: 11
107
+ span "Region: #{seller[:region]} | Sales: #{seller[:sales]}"
108
+ spacer amount: 5
109
+ end
110
+ end
111
+
112
+ section "Recommendations" do
113
+ each(:recommendations) do |rec|
114
+ paragraph "- #{rec}"
115
+ end
116
+ end
117
+
118
+ def sales_data
119
+ data[:sales] || []
120
+ end
121
+
122
+ def top_sellers
123
+ data[:top_sellers] || []
124
+ end
125
+
126
+ def recommendations
127
+ data[:recommendations] || []
128
+ end
129
+ end
130
+
131
+ # --- HR Report (Level 3) - Also Extends BaseReport ---
132
+
133
+ class HRReport < BaseReport
134
+ # Inherits: title, date, hr, spacer, summary_alert, overview section
135
+
136
+ section "Headcount Summary" do
137
+ table :headcount_data, columns: [:department, :count, :change, :openings]
138
+ end
139
+
140
+ section "Recent Hires" do
141
+ each(:recent_hires) do |hire|
142
+ paragraph "#{hire[:name]} - #{hire[:role]} (#{hire[:department]}) - Started #{hire[:start_date]}"
143
+ end
144
+ end
145
+
146
+ section "Turnover Analysis" do
147
+ alert :turnover_alert
148
+ paragraph :turnover_analysis
149
+ end
150
+
151
+ def headcount_data
152
+ data[:headcount] || []
153
+ end
154
+
155
+ def recent_hires
156
+ data[:recent_hires] || []
157
+ end
158
+
159
+ def turnover_alert
160
+ rate = data[:turnover_rate] || 0
161
+ color = rate < 10 ? "green" : rate < 20 ? "orange" : "red"
162
+ {
163
+ title: "Turnover Rate: #{rate}%",
164
+ description: rate < 10 ? "Healthy retention" : "Attention needed",
165
+ color: color
166
+ }
167
+ end
168
+
169
+ def turnover_analysis
170
+ data[:turnover_analysis] || "No analysis available."
171
+ end
172
+ end
173
+
174
+ # --- Finance Report (Level 3) - Also Extends BaseReport ---
175
+
176
+ class FinanceReport < BaseReport
177
+ # Inherits: title, date, hr, spacer, summary_alert, overview section
178
+
179
+ section "Financial Summary" do
180
+ table :financial_data, columns: [:metric, :current, :previous, :change]
181
+ end
182
+
183
+ section "Budget Status" do
184
+ each(:budget_items) do |item|
185
+ color = item[:status] == "On Track" ? "green" : item[:status] == "At Risk" ? "orange" : "red"
186
+ alert title: item[:category], description: "#{item[:spent]} of #{item[:budget]} (#{item[:status]})", color: color
187
+ end
188
+ end
189
+
190
+ section "Cash Flow" do
191
+ paragraph :cash_flow_summary
192
+ end
193
+
194
+ def financial_data
195
+ data[:financials] || []
196
+ end
197
+
198
+ def budget_items
199
+ data[:budget] || []
200
+ end
201
+
202
+ def cash_flow_summary
203
+ data[:cash_flow] || "Cash flow data not available."
204
+ end
205
+ end
206
+
207
+ # --- Generate All Three Report Types ---
208
+
209
+ puts "Generating inherited view examples...\n\n"
210
+
211
+ # 1. Sales Report
212
+ sales_data = {
213
+ doc_type: "Sales Report",
214
+ doc_id: "SR-2024-Q4-001",
215
+ title: "Q4 2024 Sales Report",
216
+ date: Date.new(2024, 12, 31),
217
+ summary: "Strong Q4 performance with 22% growth over Q3. Enterprise segment exceeded targets.",
218
+ overview: "This report covers sales performance for Q4 2024, highlighting key metrics, top performers, and strategic recommendations for Q1 2025.",
219
+
220
+ sales: [
221
+ { product: "Enterprise Suite", units: 145, revenue: "$2.1M", margin: "68%" },
222
+ { product: "Professional", units: 892, revenue: "$1.3M", margin: "72%" },
223
+ { product: "Starter", units: 2340, revenue: "$468K", margin: "81%" },
224
+ { product: "Add-ons", units: 1567, revenue: "$235K", margin: "89%" }
225
+ ],
226
+
227
+ top_sellers: [
228
+ { name: "Sarah Johnson", region: "West Coast", sales: "$890K" },
229
+ { name: "Michael Chen", region: "Northeast", sales: "$756K" },
230
+ { name: "Emily Rodriguez", region: "Southwest", sales: "$623K" }
231
+ ],
232
+
233
+ recommendations: [
234
+ "Increase Enterprise Suite marketing budget by 15%",
235
+ "Launch referral program for Professional tier",
236
+ "Expand West Coast team based on performance",
237
+ "Develop upsell path from Starter to Professional"
238
+ ]
239
+ }
240
+
241
+ sales_path = "/tmp/sales_report_inherited.pdf"
242
+ SalesReport.new(sales_data).to_file(sales_path)
243
+ puts "Generated Sales Report: #{sales_path}"
244
+
245
+ # 2. HR Report
246
+ hr_data = {
247
+ doc_type: "HR Report",
248
+ doc_id: "HR-2024-Q4-001",
249
+ title: "Q4 2024 HR Report",
250
+ date: Date.new(2024, 12, 31),
251
+ summary: "Successful hiring quarter with 28 new employees. Retention improved by 3%.",
252
+ overview: "Quarterly human resources report covering headcount, hiring, and employee retention metrics.",
253
+
254
+ headcount: [
255
+ { department: "Engineering", count: 45, change: "+8", openings: 5 },
256
+ { department: "Sales", count: 23, change: "+4", openings: 2 },
257
+ { department: "Marketing", count: 12, change: "+2", openings: 1 },
258
+ { department: "Operations", count: 18, change: "+3", openings: 0 },
259
+ { department: "Finance", count: 8, change: "+1", openings: 1 }
260
+ ],
261
+
262
+ recent_hires: [
263
+ { name: "Alex Thompson", role: "Senior Engineer", department: "Engineering", start_date: "Dec 1" },
264
+ { name: "Jessica Lee", role: "Account Executive", department: "Sales", start_date: "Nov 15" },
265
+ { name: "David Park", role: "Product Designer", department: "Engineering", start_date: "Nov 1" },
266
+ { name: "Maria Santos", role: "Marketing Manager", department: "Marketing", start_date: "Oct 15" }
267
+ ],
268
+
269
+ turnover_rate: 8,
270
+ turnover_analysis: "Q4 turnover decreased from 11% to 8%, primarily due to improved compensation " \
271
+ "packages and the new remote work policy. Engineering retention improved significantly " \
272
+ "following the technical career ladder implementation."
273
+ }
274
+
275
+ hr_path = "/tmp/hr_report_inherited.pdf"
276
+ HRReport.new(hr_data).to_file(hr_path)
277
+ puts "Generated HR Report: #{hr_path}"
278
+
279
+ # 3. Finance Report
280
+ finance_data = {
281
+ doc_type: "Finance Report",
282
+ doc_id: "FIN-2024-Q4-001",
283
+ title: "Q4 2024 Finance Report",
284
+ date: Date.new(2024, 12, 31),
285
+ summary: "Revenue exceeded forecast by 8%. Operating margin improved to 24%.",
286
+ overview: "Quarterly financial report with key metrics, budget analysis, and cash flow summary.",
287
+
288
+ financials: [
289
+ { metric: "Revenue", current: "$4.1M", previous: "$3.6M", change: "+13.9%" },
290
+ { metric: "Gross Profit", current: "$2.9M", previous: "$2.5M", change: "+16.0%" },
291
+ { metric: "Operating Expenses", current: "$1.9M", previous: "$1.8M", change: "+5.6%" },
292
+ { metric: "Net Income", current: "$980K", previous: "$720K", change: "+36.1%" },
293
+ { metric: "EBITDA", current: "$1.2M", previous: "$950K", change: "+26.3%" }
294
+ ],
295
+
296
+ budget: [
297
+ { category: "Engineering", budget: "$1.2M", spent: "$1.15M", status: "On Track" },
298
+ { category: "Sales & Marketing", budget: "$800K", spent: "$820K", status: "At Risk" },
299
+ { category: "Operations", budget: "$400K", spent: "$380K", status: "On Track" },
300
+ { category: "R&D", budget: "$600K", spent: "$720K", status: "Over Budget" }
301
+ ],
302
+
303
+ cash_flow: "Operating cash flow remained strong at $1.1M for the quarter. Major capital expenditure " \
304
+ "of $250K for infrastructure upgrades was completed. Cash reserves stand at $3.2M, " \
305
+ "providing 8 months of runway at current burn rate. Accounts receivable aging improved " \
306
+ "with DSO reduced from 45 to 38 days."
307
+ }
308
+
309
+ finance_path = "/tmp/finance_report_inherited.pdf"
310
+ FinanceReport.new(finance_data).to_file(finance_path)
311
+ puts "Generated Finance Report: #{finance_path}"
312
+
313
+ puts "\nOpening all three reports..."
314
+ system("open", sales_path)
315
+ sleep 0.5
316
+ system("open", hr_path)
317
+ sleep 0.5
318
+ system("open", finance_path)