mint 0.7.4 → 0.8.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 (70) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +23 -14
  3. data/LICENSE +22 -0
  4. data/README.md +68 -79
  5. data/bin/mint +47 -10
  6. data/bin/mint-epub +1 -4
  7. data/config/templates/base/style.css +187 -0
  8. data/config/templates/default/layout.erb +10 -0
  9. data/config/templates/default/style.css +237 -0
  10. data/config/templates/garden/layout.erb +38 -0
  11. data/config/templates/garden/style.css +303 -0
  12. data/config/templates/nord/layout.erb +11 -0
  13. data/config/templates/nord/style.css +339 -0
  14. data/config/templates/nord-dark/layout.erb +11 -0
  15. data/config/templates/nord-dark/style.css +339 -0
  16. data/config/templates/zen/layout.erb +11 -0
  17. data/config/templates/zen/style.css +114 -0
  18. data/lib/mint/command_line.rb +253 -111
  19. data/lib/mint/css.rb +11 -4
  20. data/lib/mint/css_parser.rb +76 -0
  21. data/lib/mint/css_template.rb +37 -0
  22. data/lib/mint/document.rb +203 -43
  23. data/lib/mint/helpers.rb +50 -10
  24. data/lib/mint/layout.rb +2 -3
  25. data/lib/mint/markdown_template.rb +47 -0
  26. data/lib/mint/mint.rb +181 -114
  27. data/lib/mint/plugin.rb +3 -3
  28. data/lib/mint/plugins/epub.rb +1 -2
  29. data/lib/mint/resource.rb +19 -9
  30. data/lib/mint/style.rb +10 -14
  31. data/lib/mint/version.rb +1 -1
  32. data/lib/mint.rb +1 -0
  33. data/man/mint.1 +135 -0
  34. data/spec/cli/README.md +99 -0
  35. data/spec/cli/argument_parsing_spec.rb +237 -0
  36. data/spec/cli/bin_integration_spec.rb +348 -0
  37. data/spec/cli/configuration_management_spec.rb +363 -0
  38. data/spec/cli/full_workflow_integration_spec.rb +527 -0
  39. data/spec/cli/publish_workflow_spec.rb +368 -0
  40. data/spec/cli/template_management_spec.rb +300 -0
  41. data/spec/css_parser_spec.rb +149 -0
  42. data/spec/css_spec.rb +1 -1
  43. data/spec/document_spec.rb +102 -69
  44. data/spec/helpers_spec.rb +42 -42
  45. data/spec/mint_spec.rb +104 -80
  46. data/spec/plugin_spec.rb +141 -143
  47. data/spec/run_cli_tests.rb +95 -0
  48. data/spec/spec_helper.rb +8 -1
  49. data/spec/style_spec.rb +18 -16
  50. data/spec/support/cli_helpers.rb +169 -0
  51. data/spec/support/fixtures/content-2.md +16 -0
  52. data/spec/support/matchers.rb +1 -1
  53. metadata +116 -224
  54. data/config/syntax.yaml +0 -71
  55. data/config/templates/base/style.sass +0 -144
  56. data/config/templates/default/css/style.css +0 -158
  57. data/config/templates/default/layout.haml +0 -8
  58. data/config/templates/default/style.sass +0 -36
  59. data/config/templates/protocol/layout.haml +0 -7
  60. data/config/templates/protocol/style.sass +0 -20
  61. data/config/templates/zen/css/style.css +0 -145
  62. data/config/templates/zen/layout.haml +0 -7
  63. data/config/templates/zen/style.sass +0 -24
  64. data/features/config.feature +0 -21
  65. data/features/plugins/epub.feature +0 -23
  66. data/features/publish.feature +0 -73
  67. data/features/support/env.rb +0 -15
  68. data/features/templates.feature +0 -79
  69. data/spec/command_line_spec.rb +0 -87
  70. data/spec/plugins/epub_spec.rb +0 -242
@@ -0,0 +1,363 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "CLI Configuration Management" do
4
+ describe "configuration operations" do
5
+ context "in isolated environment" do
6
+ around(:each) do |example|
7
+ in_temp_dir do |dir|
8
+ @test_dir = dir
9
+ example.run
10
+ end
11
+ end
12
+
13
+ describe "Mint::CommandLine.set" do
14
+ it "sets configuration values at local scope" do
15
+ expect {
16
+ Mint::CommandLine.set("layout", "custom", :local)
17
+ }.not_to raise_error
18
+
19
+ expect(File.exist?(".mint/config.yaml")).to be true
20
+ config = YAML.load_file(".mint/config.yaml")
21
+ expect(config["layout"]).to eq("custom")
22
+ end
23
+
24
+ it "sets configuration values at different scopes" do
25
+ # Test local scope (should work)
26
+ Mint::CommandLine.set("layout", "local-template", :local)
27
+ expect(File.exist?(".mint/config.yaml")).to be true
28
+
29
+ local_config = YAML.load_file(".mint/config.yaml")
30
+ expect(local_config["layout"]).to eq("local-template")
31
+
32
+ # For user/global scopes, we'd test the path construction
33
+ # but can't actually write to those locations in tests
34
+ end
35
+
36
+ it "creates config directory if it doesn't exist" do
37
+ expect(File.exist?(".mint")).to be false
38
+
39
+ Mint::CommandLine.set("style", "minimal", :local)
40
+
41
+ expect(File.exist?(".mint")).to be true
42
+ expect(File.directory?(".mint")).to be true
43
+ expect(File.exist?(".mint/config.yaml")).to be true
44
+ end
45
+
46
+ it "updates existing configuration values" do
47
+ # Set initial value
48
+ Mint::CommandLine.set("layout", "initial", :local)
49
+ initial_config = YAML.load_file(".mint/config.yaml")
50
+ expect(initial_config["layout"]).to eq("initial")
51
+
52
+ # Update value
53
+ Mint::CommandLine.set("layout", "updated", :local)
54
+ updated_config = YAML.load_file(".mint/config.yaml")
55
+ expect(updated_config["layout"]).to eq("updated")
56
+ end
57
+
58
+ it "preserves other configuration values" do
59
+ # Set multiple values
60
+ Mint::CommandLine.set("layout", "my-layout", :local)
61
+ Mint::CommandLine.set("style", "my-style", :local)
62
+ Mint::CommandLine.set("destination", "output", :local)
63
+
64
+ config = YAML.load_file(".mint/config.yaml")
65
+ expect(config["layout"]).to eq("my-layout")
66
+ expect(config["style"]).to eq("my-style")
67
+ expect(config["destination"]).to eq("output")
68
+
69
+ # Update one value
70
+ Mint::CommandLine.set("layout", "new-layout", :local)
71
+
72
+ updated_config = YAML.load_file(".mint/config.yaml")
73
+ expect(updated_config["layout"]).to eq("new-layout")
74
+ expect(updated_config["style"]).to eq("my-style") # preserved
75
+ expect(updated_config["destination"]).to eq("output") # preserved
76
+ end
77
+
78
+ it "handles various data types" do
79
+ Mint::CommandLine.set("string_value", "text", :local)
80
+ Mint::CommandLine.set("boolean_value", true, :local)
81
+ Mint::CommandLine.set("number_value", 42, :local)
82
+ Mint::CommandLine.set("nil_value", nil, :local)
83
+
84
+ config = YAML.load_file(".mint/config.yaml")
85
+ expect(config["string_value"]).to eq("text")
86
+ expect(config["boolean_value"]).to be true
87
+ expect(config["number_value"]).to eq(42)
88
+ expect(config["nil_value"]).to be_nil
89
+ end
90
+
91
+ it "defaults to local scope" do
92
+ Mint::CommandLine.set("test_key", "test_value") # no scope specified
93
+
94
+ expect(File.exist?(".mint/config.yaml")).to be true
95
+ config = YAML.load_file(".mint/config.yaml")
96
+ expect(config["test_key"]).to eq("test_value")
97
+ end
98
+ end
99
+
100
+ describe "Mint::CommandLine.configure" do
101
+ it "sets multiple configuration options at once" do
102
+ options = {
103
+ "layout" => "custom",
104
+ "style" => "minimal",
105
+ "destination" => "build",
106
+ "verbose" => true
107
+ }
108
+
109
+ expect {
110
+ Mint::CommandLine.configure(options, :local)
111
+ }.not_to raise_error
112
+
113
+ config = YAML.load_file(".mint/config.yaml")
114
+ expect(config["layout"]).to eq("custom")
115
+ expect(config["style"]).to eq("minimal")
116
+ expect(config["destination"]).to eq("build")
117
+ expect(config["verbose"]).to be true
118
+ end
119
+
120
+ it "merges with existing configuration" do
121
+ # Set initial config
122
+ initial_options = {
123
+ "layout" => "default",
124
+ "style" => "default",
125
+ "author" => "Test Author"
126
+ }
127
+ Mint::CommandLine.configure(initial_options, :local)
128
+
129
+ # Add more options
130
+ additional_options = {
131
+ "layout" => "updated", # should override
132
+ "destination" => "output", # should add
133
+ "verbose" => true # should add
134
+ }
135
+ Mint::CommandLine.configure(additional_options, :local)
136
+
137
+ config = YAML.load_file(".mint/config.yaml")
138
+ expect(config["layout"]).to eq("updated") # overridden
139
+ expect(config["style"]).to eq("default") # preserved
140
+ expect(config["author"]).to eq("Test Author") # preserved
141
+ expect(config["destination"]).to eq("output") # added
142
+ expect(config["verbose"]).to be true # added
143
+ end
144
+
145
+ it "handles empty options" do
146
+ expect {
147
+ Mint::CommandLine.configure({}, :local)
148
+ }.not_to raise_error
149
+
150
+ # Should create an empty config file
151
+ expect(File.exist?(".mint/config.yaml")).to be true
152
+ end
153
+
154
+ it "handles symbol keys" do
155
+ options = {
156
+ layout: "symbol-layout",
157
+ style: "symbol-style"
158
+ }
159
+
160
+ Mint::CommandLine.configure(options, :local)
161
+
162
+ config = YAML.load_file(".mint/config.yaml")
163
+ # Symbol keys remain as symbols in YAML
164
+ expect(config[:layout]).to eq("symbol-layout")
165
+ expect(config[:style]).to eq("symbol-style")
166
+ end
167
+ end
168
+
169
+ describe "Mint::CommandLine.config" do
170
+ it "displays current configuration" do
171
+ # Set up some configuration
172
+ Mint::CommandLine.set("layout", "test-layout", :local)
173
+ Mint::CommandLine.set("style", "test-style", :local)
174
+
175
+ stdout, stderr = capture_output do
176
+ Mint::CommandLine.config
177
+ end
178
+
179
+ expect(stdout).to include("layout")
180
+ expect(stdout).to include("test-layout")
181
+ expect(stdout).to include("style")
182
+ expect(stdout).to include("test-style")
183
+ end
184
+
185
+ it "shows empty configuration when none exists" do
186
+ stdout, stderr = capture_output do
187
+ Mint::CommandLine.config
188
+ end
189
+
190
+ # Should show default configuration or empty YAML
191
+ expect(stdout).to include("---") # YAML document start
192
+ end
193
+
194
+ it "merges configuration from multiple scopes" do
195
+ # This is more complex to test since we can't easily create
196
+ # user/global configs, but we can test the concept
197
+ setup_basic_config(:local)
198
+
199
+ stdout, stderr = capture_output do
200
+ Mint::CommandLine.config
201
+ end
202
+
203
+ expect(stdout).to include("layout")
204
+ expect(stdout).to include("default")
205
+ end
206
+ end
207
+
208
+ describe "configuration precedence and merging" do
209
+ describe "Mint.configuration" do
210
+ it "provides default configuration when no files exist" do
211
+ config = Mint.configuration
212
+
213
+ expect(config).to be_a(Hash)
214
+ expect(config[:layout_or_style_or_template]).to eq([:template, "default"])
215
+ end
216
+
217
+ it "merges local configuration with defaults" do
218
+ Mint::CommandLine.set("layout", "custom", :local)
219
+ Mint::CommandLine.set("author", "Test Author", :local)
220
+
221
+ config = Mint.configuration
222
+
223
+ expect(config[:layout]).to eq("custom") # from local config
224
+ expect(config[:layout_or_style_or_template]).to eq([:template, "default"]) # from defaults
225
+ expect(config[:author]).to eq("Test Author") # from local config
226
+ end
227
+ end
228
+
229
+ describe "Mint.configuration_with" do
230
+ it "merges additional options with configuration" do
231
+ Mint::CommandLine.set("layout", "from-config", :local)
232
+
233
+ config = Mint.configuration_with({
234
+ style: "from-options",
235
+ destination: "custom-dest"
236
+ })
237
+
238
+ expect(config[:layout]).to eq("from-config") # from config file
239
+ expect(config[:style]).to eq("from-options") # from options
240
+ expect(config[:destination]).to eq("custom-dest") # from options
241
+ end
242
+
243
+ it "allows options to override configuration" do
244
+ Mint::CommandLine.set("layout", "config-layout", :local)
245
+ Mint::CommandLine.set("style", "config-style", :local)
246
+
247
+ config = Mint.configuration_with({
248
+ layout: "override-layout" # should override config
249
+ })
250
+
251
+ expect(config[:layout]).to eq("override-layout") # overridden
252
+ expect(config[:style]).to eq("config-style") # preserved
253
+ end
254
+
255
+ it "handles scope-specific configuration" do
256
+ # Test that scope flags affect which configs are loaded
257
+ # This is more complex but important for the new scope system
258
+ setup_basic_config(:local)
259
+
260
+ # Test with different scope selections
261
+ config_local = Mint.configuration_with({ scope: :local })
262
+ config_with_defaults = Mint.configuration_with({})
263
+
264
+ expect(config_local).to include(:layout)
265
+ expect(config_with_defaults).to include(:layout)
266
+ end
267
+ end
268
+ end
269
+
270
+ describe "configuration file handling" do
271
+ it "creates valid YAML files" do
272
+ Mint::CommandLine.set("test", "value", :local)
273
+
274
+ expect(File.exist?(".mint/config.yaml")).to be true
275
+
276
+ # Should be parseable YAML
277
+ expect {
278
+ YAML.load_file(".mint/config.yaml")
279
+ }.not_to raise_error
280
+ end
281
+
282
+ it "handles special characters in values" do
283
+ special_values = {
284
+ "quotes" => 'Value with "quotes"',
285
+ "newlines" => "Line 1\nLine 2",
286
+ "unicode" => "Unicode: 中文 🚀",
287
+ "symbols" => "Symbols: @#$%^&*()"
288
+ }
289
+
290
+ special_values.each do |key, value|
291
+ Mint::CommandLine.set(key, value, :local)
292
+ end
293
+
294
+ config = YAML.load_file(".mint/config.yaml")
295
+ special_values.each do |key, expected_value|
296
+ expect(config[key]).to eq(expected_value)
297
+ end
298
+ end
299
+
300
+ it "handles concurrent access gracefully" do
301
+ # This is difficult to test properly, but we can at least
302
+ # verify that multiple rapid operations don't corrupt the file
303
+ 10.times do |i|
304
+ Mint::CommandLine.set("key#{i}", "value#{i}", :local)
305
+ end
306
+
307
+ config = YAML.load_file(".mint/config.yaml")
308
+ 10.times do |i|
309
+ expect(config["key#{i}"]).to eq("value#{i}")
310
+ end
311
+ end
312
+
313
+ it "preserves file permissions" do
314
+ Mint::CommandLine.set("test", "value", :local)
315
+
316
+ file_stat = File.stat(".mint/config.yaml")
317
+ original_mode = file_stat.mode
318
+
319
+ Mint::CommandLine.set("test2", "value2", :local)
320
+
321
+ new_file_stat = File.stat(".mint/config.yaml")
322
+ expect(new_file_stat.mode).to eq(original_mode)
323
+ end
324
+ end
325
+
326
+ describe "error handling" do
327
+ it "handles invalid YAML gracefully" do
328
+ # Create an invalid YAML file
329
+ FileUtils.mkdir_p(".mint")
330
+ File.write(".mint/config.yaml", "invalid: yaml: content: [unclosed")
331
+
332
+ expect {
333
+ Mint.configuration
334
+ }.not_to raise_error # Should handle gracefully
335
+ end
336
+
337
+ it "handles permission errors" do
338
+ # Create config directory but make it read-only
339
+ FileUtils.mkdir_p(".mint")
340
+ File.chmod(0444, ".mint")
341
+
342
+ begin
343
+ expect {
344
+ Mint::CommandLine.set("test", "value", :local)
345
+ }.to raise_error(Errno::EACCES) # Should fail due to permissions
346
+ ensure
347
+ # Restore permissions for cleanup
348
+ File.chmod(0755, ".mint")
349
+ end
350
+ end
351
+
352
+ it "handles missing parent directories" do
353
+ # This should work - the set method should create directories
354
+ expect {
355
+ Mint::CommandLine.set("test", "value", :local)
356
+ }.not_to raise_error
357
+
358
+ expect(File.exist?(".mint/config.yaml")).to be true
359
+ end
360
+ end
361
+ end
362
+ end
363
+ end