cov-loupe 3.0.0 → 4.0.0.pre

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 (281) hide show
  1. checksums.yaml +4 -4
  2. data/AGENTS.md +230 -0
  3. data/CLAUDE.md +5 -0
  4. data/CODE_OF_CONDUCT.md +62 -0
  5. data/CONTRIBUTING.md +102 -0
  6. data/GEMINI.md +5 -0
  7. data/README.md +154 -51
  8. data/RELEASE_NOTES.md +452 -0
  9. data/dev/images/cov-loupe-icon-lores.png +0 -0
  10. data/dev/images/cov-loupe-icon-square.png +0 -0
  11. data/dev/images/cov-loupe-icon.png +0 -0
  12. data/dev/images/cov-loupe-logo.png +0 -0
  13. data/dev/prompts/README.md +74 -0
  14. data/dev/prompts/archive/architectural-review-and-actions-prompt.md +53 -0
  15. data/dev/prompts/archive/investigate-and-report-issues-prompt.md +33 -0
  16. data/dev/prompts/archive/produce-action-items-prompt.md +25 -0
  17. data/dev/prompts/guidelines/ai-code-evaluator-guidelines.md +337 -0
  18. data/dev/prompts/improve/refactor-test-suite.md +18 -0
  19. data/dev/prompts/improve/simplify-code-logic.md +133 -0
  20. data/dev/prompts/improve/update-documentation.md +21 -0
  21. data/dev/prompts/review/comprehensive-codebase-review.md +176 -0
  22. data/dev/prompts/review/identify-action-items.md +143 -0
  23. data/dev/prompts/review/verify-code-changes.md +54 -0
  24. data/dev/prompts/validate/create-screencast-outline.md +234 -0
  25. data/dev/prompts/validate/test-documentation-examples.md +180 -0
  26. data/docs/QUICKSTART.md +63 -0
  27. data/docs/assets/images/cov-loupe-logo-lores.png +0 -0
  28. data/docs/assets/images/cov-loupe-logo.png +0 -0
  29. data/docs/assets/images/favicon.png +0 -0
  30. data/docs/assets/stylesheets/branding.css +16 -0
  31. data/docs/assets/stylesheets/extra.css +15 -0
  32. data/docs/code_of_conduct.md +1 -0
  33. data/docs/contributing.md +1 -0
  34. data/docs/dev/ARCHITECTURE.md +56 -11
  35. data/docs/dev/DEVELOPMENT.md +116 -12
  36. data/docs/dev/FUTURE_ENHANCEMENTS.md +14 -0
  37. data/docs/dev/README.md +3 -2
  38. data/docs/dev/RELEASING.md +2 -0
  39. data/docs/dev/arch-decisions/README.md +10 -7
  40. data/docs/dev/arch-decisions/application-architecture.md +259 -0
  41. data/docs/dev/arch-decisions/coverage-data-quality.md +193 -0
  42. data/docs/dev/arch-decisions/output-character-mode.md +217 -0
  43. data/docs/dev/arch-decisions/path-resolution.md +90 -0
  44. data/docs/dev/arch-decisions/{004-x-arch-decision.md → policy-validation.md} +32 -28
  45. data/docs/dev/arch-decisions/{005-x-arch-decision.md → simplecov-integration.md} +47 -44
  46. data/docs/dev/presentations/cov-loupe-presentation.md +15 -13
  47. data/docs/examples/mcp-inputs.md +3 -0
  48. data/docs/examples/prompts.md +3 -0
  49. data/docs/examples/success_predicates.md +3 -0
  50. data/docs/fixtures/demo_project/.resultset.json +170 -0
  51. data/docs/fixtures/demo_project/README.md +6 -0
  52. data/docs/fixtures/demo_project/app/controllers/admin/audit_logs_controller.rb +19 -0
  53. data/docs/fixtures/demo_project/app/controllers/orders_controller.rb +26 -0
  54. data/docs/fixtures/demo_project/app/models/order.rb +20 -0
  55. data/docs/fixtures/demo_project/app/models/user.rb +19 -0
  56. data/docs/fixtures/demo_project/lib/api/client.rb +22 -0
  57. data/docs/fixtures/demo_project/lib/ops/jobs/cleanup_job.rb +16 -0
  58. data/docs/fixtures/demo_project/lib/ops/jobs/report_job.rb +17 -0
  59. data/docs/fixtures/demo_project/lib/payments/processor.rb +15 -0
  60. data/docs/fixtures/demo_project/lib/payments/refund_service.rb +15 -0
  61. data/docs/fixtures/demo_project/lib/payments/reporting/exporter.rb +16 -0
  62. data/docs/index.md +1 -0
  63. data/docs/license.md +3 -0
  64. data/docs/release_notes.md +3 -0
  65. data/docs/user/ADVANCED_USAGE.md +208 -115
  66. data/docs/user/CLI_FALLBACK_FOR_LLMS.md +2 -0
  67. data/docs/user/CLI_USAGE.md +276 -101
  68. data/docs/user/ERROR_HANDLING.md +4 -4
  69. data/docs/user/EXAMPLES.md +121 -128
  70. data/docs/user/INSTALLATION.md +9 -28
  71. data/docs/user/LIBRARY_API.md +227 -122
  72. data/docs/user/MCP_INTEGRATION.md +114 -203
  73. data/docs/user/README.md +5 -1
  74. data/docs/user/TROUBLESHOOTING.md +49 -27
  75. data/docs/user/installing-a-prelease-version-of-covloupe.md +43 -0
  76. data/docs/user/{V2-BREAKING-CHANGES.md → migrations/MIGRATING_TO_V2.md} +62 -72
  77. data/docs/user/migrations/MIGRATING_TO_V3.md +72 -0
  78. data/docs/user/migrations/MIGRATING_TO_V4.md +591 -0
  79. data/docs/user/migrations/README.md +22 -0
  80. data/docs/user/prompts/README.md +9 -0
  81. data/docs/user/prompts/non-web-coverage-analysis-prompt.md +103 -0
  82. data/docs/user/prompts/rails-coverage-analysis-prompt.md +94 -0
  83. data/docs/user/prompts/use-cli-not-mcp-prompt.md +53 -0
  84. data/examples/cli_demo.sh +77 -0
  85. data/examples/filter_and_table_demo-output.md +114 -0
  86. data/examples/filter_and_table_demo.rb +174 -0
  87. data/examples/fixtures/demo_project/coverage/.resultset.json +10 -0
  88. data/examples/mcp-inputs/README.md +66 -0
  89. data/examples/mcp-inputs/coverage_detailed.json +1 -0
  90. data/examples/mcp-inputs/coverage_raw.json +1 -0
  91. data/examples/mcp-inputs/coverage_summary.json +1 -0
  92. data/examples/mcp-inputs/list.json +1 -0
  93. data/examples/mcp-inputs/uncovered_lines.json +1 -0
  94. data/examples/prompts/README.md +27 -0
  95. data/examples/prompts/custom_resultset.txt +2 -0
  96. data/examples/prompts/detailed_with_source.txt +2 -0
  97. data/examples/prompts/list_lowest.txt +2 -0
  98. data/examples/prompts/summary.txt +2 -0
  99. data/examples/prompts/uncovered.txt +2 -0
  100. data/examples/success_predicates/README.md +198 -0
  101. data/examples/success_predicates/all_files_above_threshold_predicate.rb +21 -0
  102. data/examples/success_predicates/directory_specific_thresholds_predicate.rb +30 -0
  103. data/examples/success_predicates/project_coverage_minimum_predicate.rb +6 -0
  104. data/lib/cov_loupe/base_tool.rb +229 -20
  105. data/lib/cov_loupe/cli.rb +132 -23
  106. data/lib/cov_loupe/commands/base_command.rb +25 -6
  107. data/lib/cov_loupe/commands/command_factory.rb +0 -1
  108. data/lib/cov_loupe/commands/detailed_command.rb +10 -5
  109. data/lib/cov_loupe/commands/list_command.rb +2 -1
  110. data/lib/cov_loupe/commands/raw_command.rb +7 -5
  111. data/lib/cov_loupe/commands/summary_command.rb +12 -7
  112. data/lib/cov_loupe/commands/totals_command.rb +74 -10
  113. data/lib/cov_loupe/commands/uncovered_command.rb +7 -5
  114. data/lib/cov_loupe/commands/validate_command.rb +11 -3
  115. data/lib/cov_loupe/commands/version_command.rb +6 -4
  116. data/lib/cov_loupe/{app_config.rb → config/app_config.rb} +13 -5
  117. data/lib/cov_loupe/config/app_context.rb +43 -0
  118. data/lib/cov_loupe/config/boolean_type.rb +91 -0
  119. data/lib/cov_loupe/config/logger.rb +92 -0
  120. data/lib/cov_loupe/{option_normalizers.rb → config/option_normalizers.rb} +55 -24
  121. data/lib/cov_loupe/{option_parser_builder.rb → config/option_parser_builder.rb} +46 -24
  122. data/lib/cov_loupe/coverage/coverage_calculator.rb +53 -0
  123. data/lib/cov_loupe/coverage/coverage_reporter.rb +63 -0
  124. data/lib/cov_loupe/coverage/coverage_table_formatter.rb +133 -0
  125. data/lib/cov_loupe/{error_handler.rb → errors/error_handler.rb} +21 -33
  126. data/lib/cov_loupe/{errors.rb → errors/errors.rb} +48 -71
  127. data/lib/cov_loupe/formatters/formatters.rb +75 -0
  128. data/lib/cov_loupe/formatters/source_formatter.rb +18 -7
  129. data/lib/cov_loupe/formatters/table_formatter.rb +80 -0
  130. data/lib/cov_loupe/loaders/all.rb +15 -0
  131. data/lib/cov_loupe/loaders/all_cli.rb +10 -0
  132. data/lib/cov_loupe/loaders/all_mcp.rb +23 -0
  133. data/lib/cov_loupe/loaders/resultset_loader.rb +147 -0
  134. data/lib/cov_loupe/mcp_server.rb +3 -2
  135. data/lib/cov_loupe/model/model.rb +520 -0
  136. data/lib/cov_loupe/model/model_data.rb +13 -0
  137. data/lib/cov_loupe/model/model_data_cache.rb +116 -0
  138. data/lib/cov_loupe/option_parsers/env_options_parser.rb +17 -6
  139. data/lib/cov_loupe/option_parsers/error_helper.rb +16 -10
  140. data/lib/cov_loupe/output_chars.rb +192 -0
  141. data/lib/cov_loupe/paths/glob_utils.rb +100 -0
  142. data/lib/cov_loupe/{path_relativizer.rb → paths/path_relativizer.rb} +5 -13
  143. data/lib/cov_loupe/paths/path_utils.rb +265 -0
  144. data/lib/cov_loupe/paths/volume_case_sensitivity.rb +173 -0
  145. data/lib/cov_loupe/presenters/base_coverage_presenter.rb +9 -13
  146. data/lib/cov_loupe/presenters/coverage_payload_presenter.rb +21 -0
  147. data/lib/cov_loupe/presenters/payload_caching.rb +23 -0
  148. data/lib/cov_loupe/presenters/project_coverage_presenter.rb +73 -21
  149. data/lib/cov_loupe/presenters/project_totals_presenter.rb +16 -10
  150. data/lib/cov_loupe/repositories/coverage_repository.rb +149 -0
  151. data/lib/cov_loupe/resolvers/coverage_line_resolver.rb +90 -76
  152. data/lib/cov_loupe/resolvers/{resolver_factory.rb → resolver_helpers.rb} +6 -5
  153. data/lib/cov_loupe/resolvers/resultset_path_resolver.rb +40 -12
  154. data/lib/cov_loupe/scripts/command_execution.rb +113 -0
  155. data/lib/cov_loupe/scripts/latest_ci_status.rb +97 -0
  156. data/lib/cov_loupe/scripts/pre_release_check.rb +164 -0
  157. data/lib/cov_loupe/scripts/setup_doc_server.rb +23 -0
  158. data/lib/cov_loupe/scripts/start_doc_server.rb +24 -0
  159. data/lib/cov_loupe/staleness/stale_status.rb +23 -0
  160. data/lib/cov_loupe/staleness/staleness_checker.rb +328 -0
  161. data/lib/cov_loupe/staleness/staleness_message_formatter.rb +91 -0
  162. data/lib/cov_loupe/tools/coverage_detailed_tool.rb +14 -15
  163. data/lib/cov_loupe/tools/coverage_raw_tool.rb +14 -14
  164. data/lib/cov_loupe/tools/coverage_summary_tool.rb +16 -16
  165. data/lib/cov_loupe/tools/coverage_table_tool.rb +139 -21
  166. data/lib/cov_loupe/tools/coverage_totals_tool.rb +31 -13
  167. data/lib/cov_loupe/tools/help_tool.rb +16 -20
  168. data/lib/cov_loupe/tools/list_tool.rb +65 -0
  169. data/lib/cov_loupe/tools/uncovered_lines_tool.rb +14 -14
  170. data/lib/cov_loupe/tools/validate_tool.rb +18 -24
  171. data/lib/cov_loupe/tools/version_tool.rb +8 -3
  172. data/lib/cov_loupe/version.rb +1 -1
  173. data/lib/cov_loupe.rb +83 -55
  174. metadata +184 -154
  175. data/docs/dev/BRANCH_ONLY_COVERAGE.md +0 -158
  176. data/docs/dev/arch-decisions/001-x-arch-decision.md +0 -95
  177. data/docs/dev/arch-decisions/002-x-arch-decision.md +0 -159
  178. data/docs/dev/arch-decisions/003-x-arch-decision.md +0 -165
  179. data/lib/cov_loupe/app_context.rb +0 -26
  180. data/lib/cov_loupe/constants.rb +0 -22
  181. data/lib/cov_loupe/coverage_reporter.rb +0 -31
  182. data/lib/cov_loupe/formatters.rb +0 -51
  183. data/lib/cov_loupe/mode_detector.rb +0 -56
  184. data/lib/cov_loupe/model.rb +0 -339
  185. data/lib/cov_loupe/presenters/coverage_detailed_presenter.rb +0 -14
  186. data/lib/cov_loupe/presenters/coverage_raw_presenter.rb +0 -14
  187. data/lib/cov_loupe/presenters/coverage_summary_presenter.rb +0 -14
  188. data/lib/cov_loupe/presenters/coverage_uncovered_presenter.rb +0 -14
  189. data/lib/cov_loupe/resultset_loader.rb +0 -131
  190. data/lib/cov_loupe/staleness_checker.rb +0 -247
  191. data/lib/cov_loupe/table_formatter.rb +0 -64
  192. data/lib/cov_loupe/tools/all_files_coverage_tool.rb +0 -51
  193. data/lib/cov_loupe/util.rb +0 -88
  194. data/spec/MCP_INTEGRATION_TESTS_README.md +0 -111
  195. data/spec/TIMESTAMPS.md +0 -48
  196. data/spec/all_files_coverage_tool_spec.rb +0 -53
  197. data/spec/app_config_spec.rb +0 -142
  198. data/spec/base_tool_spec.rb +0 -62
  199. data/spec/cli/show_default_report_spec.rb +0 -33
  200. data/spec/cli_enumerated_options_spec.rb +0 -90
  201. data/spec/cli_error_spec.rb +0 -184
  202. data/spec/cli_format_spec.rb +0 -123
  203. data/spec/cli_json_options_spec.rb +0 -50
  204. data/spec/cli_source_spec.rb +0 -44
  205. data/spec/cli_spec.rb +0 -192
  206. data/spec/cli_table_spec.rb +0 -28
  207. data/spec/cli_usage_spec.rb +0 -42
  208. data/spec/commands/base_command_spec.rb +0 -107
  209. data/spec/commands/command_factory_spec.rb +0 -76
  210. data/spec/commands/detailed_command_spec.rb +0 -34
  211. data/spec/commands/list_command_spec.rb +0 -28
  212. data/spec/commands/raw_command_spec.rb +0 -69
  213. data/spec/commands/summary_command_spec.rb +0 -34
  214. data/spec/commands/totals_command_spec.rb +0 -34
  215. data/spec/commands/uncovered_command_spec.rb +0 -55
  216. data/spec/commands/validate_command_spec.rb +0 -213
  217. data/spec/commands/version_command_spec.rb +0 -38
  218. data/spec/constants_spec.rb +0 -61
  219. data/spec/cov_loupe/formatters/source_formatter_spec.rb +0 -267
  220. data/spec/cov_loupe/formatters_spec.rb +0 -76
  221. data/spec/cov_loupe/presenters/base_coverage_presenter_spec.rb +0 -79
  222. data/spec/cov_loupe_model_spec.rb +0 -454
  223. data/spec/cov_loupe_module_spec.rb +0 -37
  224. data/spec/cov_loupe_opts_spec.rb +0 -185
  225. data/spec/coverage_reporter_spec.rb +0 -102
  226. data/spec/coverage_table_tool_spec.rb +0 -59
  227. data/spec/coverage_totals_tool_spec.rb +0 -37
  228. data/spec/error_handler_spec.rb +0 -197
  229. data/spec/error_mode_spec.rb +0 -139
  230. data/spec/errors_edge_cases_spec.rb +0 -312
  231. data/spec/errors_stale_spec.rb +0 -83
  232. data/spec/file_based_mcp_tools_spec.rb +0 -99
  233. data/spec/help_tool_spec.rb +0 -26
  234. data/spec/integration_spec.rb +0 -789
  235. data/spec/logging_fallback_spec.rb +0 -128
  236. data/spec/mcp_logging_spec.rb +0 -44
  237. data/spec/mcp_server_integration_spec.rb +0 -23
  238. data/spec/mcp_server_spec.rb +0 -106
  239. data/spec/mode_detector_spec.rb +0 -153
  240. data/spec/model_error_handling_spec.rb +0 -269
  241. data/spec/model_staleness_spec.rb +0 -79
  242. data/spec/option_normalizers_spec.rb +0 -203
  243. data/spec/option_parsers/env_options_parser_spec.rb +0 -221
  244. data/spec/option_parsers/error_helper_spec.rb +0 -222
  245. data/spec/path_relativizer_spec.rb +0 -98
  246. data/spec/presenters/coverage_detailed_presenter_spec.rb +0 -19
  247. data/spec/presenters/coverage_raw_presenter_spec.rb +0 -15
  248. data/spec/presenters/coverage_summary_presenter_spec.rb +0 -15
  249. data/spec/presenters/coverage_uncovered_presenter_spec.rb +0 -16
  250. data/spec/presenters/project_coverage_presenter_spec.rb +0 -87
  251. data/spec/presenters/project_totals_presenter_spec.rb +0 -144
  252. data/spec/resolvers/coverage_line_resolver_spec.rb +0 -282
  253. data/spec/resolvers/resolver_factory_spec.rb +0 -61
  254. data/spec/resolvers/resultset_path_resolver_spec.rb +0 -60
  255. data/spec/resultset_loader_spec.rb +0 -167
  256. data/spec/shared_examples/README.md +0 -115
  257. data/spec/shared_examples/coverage_presenter_examples.rb +0 -66
  258. data/spec/shared_examples/file_based_mcp_tools.rb +0 -179
  259. data/spec/shared_examples/formatted_command_examples.rb +0 -64
  260. data/spec/shared_examples/mcp_tool_text_json_response.rb +0 -16
  261. data/spec/spec_helper.rb +0 -127
  262. data/spec/staleness_checker_spec.rb +0 -374
  263. data/spec/staleness_more_spec.rb +0 -42
  264. data/spec/support/cli_helpers.rb +0 -22
  265. data/spec/support/control_flow_helpers.rb +0 -20
  266. data/spec/support/fake_mcp.rb +0 -40
  267. data/spec/support/io_helpers.rb +0 -29
  268. data/spec/support/mcp_helpers.rb +0 -35
  269. data/spec/support/mcp_runner.rb +0 -66
  270. data/spec/support/mocking_helpers.rb +0 -30
  271. data/spec/table_format_spec.rb +0 -70
  272. data/spec/tools/validate_tool_spec.rb +0 -132
  273. data/spec/tools_error_handling_spec.rb +0 -130
  274. data/spec/util_spec.rb +0 -154
  275. data/spec/version_spec.rb +0 -123
  276. data/spec/version_tool_spec.rb +0 -141
  277. /data/{spec/fixtures/project1 → examples/fixtures/demo_project}/lib/bar.rb +0 -0
  278. /data/{spec/fixtures/project1 → examples/fixtures/demo_project}/lib/foo.rb +0 -0
  279. /data/lib/cov_loupe/{config_parser.rb → config/config_parser.rb} +0 -0
  280. /data/lib/cov_loupe/{predicate_evaluator.rb → config/predicate_evaluator.rb} +0 -0
  281. /data/lib/cov_loupe/{error_handler_factory.rb → errors/error_handler_factory.rb} +0 -0
@@ -0,0 +1,170 @@
1
+ {
2
+ "DemoSuite": {
3
+ "coverage": {
4
+ "app/models/user.rb": {
5
+ "lines": [
6
+ null,
7
+ null,
8
+ null,
9
+ null,
10
+ null,
11
+ 1,
12
+ 1,
13
+ null,
14
+ null,
15
+ 1,
16
+ 1,
17
+ null,
18
+ null,
19
+ 1,
20
+ 1,
21
+ null,
22
+ null,
23
+ null,
24
+ null
25
+ ]
26
+ },
27
+ "app/models/order.rb": {
28
+ "lines": [
29
+ null,
30
+ null,
31
+ null,
32
+ null,
33
+ null,
34
+ 1,
35
+ 1,
36
+ 1,
37
+ null,
38
+ null,
39
+ 1,
40
+ 1,
41
+ null,
42
+ null,
43
+ 1,
44
+ 0,
45
+ null,
46
+ null,
47
+ null,
48
+ null
49
+ ]
50
+ },
51
+ "app/controllers/orders_controller.rb": {
52
+ "lines": [
53
+ null,
54
+ null,
55
+ null,
56
+ null,
57
+ null,
58
+ 1,
59
+ 1,
60
+ null,
61
+ null,
62
+ 1,
63
+ 1,
64
+ null,
65
+ null,
66
+ 0,
67
+ 0,
68
+ null,
69
+ null,
70
+ 1,
71
+ 1,
72
+ 0,
73
+ null,
74
+ 1,
75
+ null,
76
+ null,
77
+ null,
78
+ null
79
+ ]
80
+ },
81
+ "lib/payments/processor.rb": {
82
+ "lines": [
83
+ null,
84
+ null,
85
+ null,
86
+ null,
87
+ 1,
88
+ 1,
89
+ null,
90
+ null,
91
+ 1,
92
+ 0,
93
+ null,
94
+ 1,
95
+ null,
96
+ null,
97
+ null
98
+ ]
99
+ },
100
+ "lib/payments/refund_service.rb": {
101
+ "lines": [
102
+ null,
103
+ null,
104
+ null,
105
+ null,
106
+ 1,
107
+ 1,
108
+ null,
109
+ null,
110
+ 1,
111
+ 0,
112
+ null,
113
+ 0,
114
+ null,
115
+ null,
116
+ null
117
+ ]
118
+ },
119
+ "lib/ops/jobs/report_job.rb": {
120
+ "lines": [
121
+ null,
122
+ null,
123
+ null,
124
+ null,
125
+ null,
126
+ 1,
127
+ 1,
128
+ null,
129
+ null,
130
+ 1,
131
+ 0,
132
+ null,
133
+ 1,
134
+ null,
135
+ null,
136
+ null,
137
+ null
138
+ ]
139
+ },
140
+ "lib/api/client.rb": {
141
+ "lines": [
142
+ null,
143
+ null,
144
+ null,
145
+ null,
146
+ 1,
147
+ 1,
148
+ 1,
149
+ null,
150
+ null,
151
+ 1,
152
+ 1,
153
+ null,
154
+ null,
155
+ 1,
156
+ 0,
157
+ null,
158
+ null,
159
+ null,
160
+ null,
161
+ 1,
162
+ 1,
163
+ null
164
+ ]
165
+ }
166
+ },
167
+ "timestamp": 1765371086,
168
+ "command_name": "demo"
169
+ }
170
+ }
@@ -1,5 +1,7 @@
1
1
  # Demo project fixture
2
2
 
3
+ [Back to docs index](../../index.md)
4
+
3
5
  This small demo project powers the documentation examples that rely on partial coverage and tracked globs.
4
6
 
5
7
  - Location: `docs/fixtures/demo_project`
@@ -7,3 +9,7 @@ This small demo project powers the documentation examples that rely on partial c
7
9
  - Suggested alias for docs: `alias clp='cov-loupe --root docs/fixtures/demo_project'`
8
10
 
9
11
  Files include controllers, models, payments services, background jobs, and an API client. A few files are intentionally missing from the resultset so the `--tracked-globs` examples surface gaps.
12
+
13
+ Related guides:
14
+ - [CLI Usage](../../user/CLI_USAGE.md)
15
+ - [Examples](../../user/EXAMPLES.md)
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DemoApp
4
+ module Controllers
5
+ module Admin
6
+ class AuditLogsController
7
+ def initialize(logger:)
8
+ @logger = logger
9
+ end
10
+
11
+ def capture(event)
12
+ return if event.nil? || event[:action].to_s.empty?
13
+
14
+ @logger.info("audit=#{event[:action]} user=#{event[:user]}")
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DemoApp
4
+ module Controllers
5
+ class OrdersController
6
+ def initialize(repo:)
7
+ @repo = repo
8
+ end
9
+
10
+ def index
11
+ @repo.all
12
+ end
13
+
14
+ def show(id)
15
+ @repo.find(id)
16
+ end
17
+
18
+ def cancel(id)
19
+ order = @repo.find(id)
20
+ return :missing unless order
21
+
22
+ @repo.cancel(id)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DemoApp
4
+ module Models
5
+ class Order
6
+ def initialize(id:, total_cents:)
7
+ @id = id
8
+ @total_cents = total_cents
9
+ end
10
+
11
+ def total_dollars
12
+ (@total_cents / 100.0).round(2)
13
+ end
14
+
15
+ def expensive?(threshold_cents = 10_000)
16
+ @total_cents >= threshold_cents
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DemoApp
4
+ module Models
5
+ class User
6
+ def initialize(attrs = {})
7
+ @attrs = attrs
8
+ end
9
+
10
+ def admin?
11
+ @attrs.fetch(:role, 'user') == 'admin'
12
+ end
13
+
14
+ def active?
15
+ @attrs.fetch(:status, 'active') == 'active'
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Api
4
+ class Client
5
+ def initialize(base_url:, http:)
6
+ @base_url = base_url
7
+ @http = http
8
+ end
9
+
10
+ def get(path)
11
+ @http.get(url_for(path))
12
+ end
13
+
14
+ def post(path, body)
15
+ @http.post(url_for(path), body: body)
16
+ end
17
+
18
+ private def url_for(path)
19
+ "#{@base_url}/#{path}"
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ops
4
+ module Jobs
5
+ class CleanupJob
6
+ def initialize(storage:)
7
+ @storage = storage
8
+ end
9
+
10
+ def perform
11
+ @storage.prune!
12
+ :ok
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ops
4
+ module Jobs
5
+ class ReportJob
6
+ def initialize(exporter:)
7
+ @exporter = exporter
8
+ end
9
+
10
+ def perform(rows)
11
+ return :no_data if rows.empty?
12
+
13
+ @exporter.export(rows)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Payments
4
+ class Processor
5
+ def initialize(gateway:)
6
+ @gateway = gateway
7
+ end
8
+
9
+ def charge(user_id:, cents:)
10
+ raise ArgumentError, 'amount must be positive' if cents.to_i <= 0
11
+
12
+ @gateway.charge(user_id: user_id, cents: cents)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Payments
4
+ class RefundService
5
+ def initialize(processor:)
6
+ @processor = processor
7
+ end
8
+
9
+ def refund(order_id:, cents:)
10
+ return :invalid if cents.to_i <= 0
11
+
12
+ @processor.refund(order_id: order_id, cents: cents)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Payments
4
+ module Reporting
5
+ class Exporter
6
+ def initialize(writer:)
7
+ @writer = writer
8
+ end
9
+
10
+ def export(rows)
11
+ rows.each { |row| @writer.write(row) }
12
+ @writer.flush
13
+ end
14
+ end
15
+ end
16
+ end
data/docs/index.md ADDED
@@ -0,0 +1 @@
1
+ {% include-markdown "../README.md" %}
data/docs/license.md ADDED
@@ -0,0 +1,3 @@
1
+ # License
2
+
3
+ {% include-markdown "../LICENSE" %}
@@ -0,0 +1,3 @@
1
+ # Release Notes
2
+
3
+ {% include-markdown "../RELEASE_NOTES.md" %}