automatic 26.08 → 26.09

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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +80 -46
  3. data/VERSION +1 -1
  4. data/assets/siteinfo/items_all.json +60300 -52138
  5. data/automatic.gemspec +4 -3
  6. data/bin/automatic +1 -1
  7. data/doc/AI_TUTORIAL.md +64 -40
  8. data/doc/BASIC_DESIGN.md +31 -0
  9. data/doc/DEPLOYMENT.md +53 -47
  10. data/doc/PLUGINS.md +231 -91
  11. data/doc/POLICY.md +149 -44
  12. data/doc/QUICKSTART.md +19 -15
  13. data/doc/RELEASING.md +20 -7
  14. data/doc/REQUIREMENTS.md +40 -10
  15. data/doc/VERSIONS +112 -54
  16. data/lib/automatic/cli.rb +40 -18
  17. data/lib/automatic/environment.rb +1 -1
  18. data/lib/automatic/feed_maker.rb +57 -18
  19. data/lib/automatic/feed_parser.rb +1 -1
  20. data/lib/automatic/http.rb +1 -1
  21. data/lib/automatic/log.rb +1 -1
  22. data/lib/automatic/pipeline.rb +15 -5
  23. data/lib/automatic/recipe.rb +45 -1
  24. data/lib/automatic/version.rb +3 -3
  25. data/lib/automatic.rb +18 -3
  26. data/plugins/custom_feed/web.rb +1 -1
  27. data/plugins/filter/absolute_uri.rb +1 -1
  28. data/plugins/filter/batch.rb +97 -0
  29. data/plugins/filter/claude.rb +1 -1
  30. data/plugins/filter/clear.rb +1 -1
  31. data/plugins/filter/description_link.rb +20 -3
  32. data/plugins/filter/full_feed.rb +28 -16
  33. data/plugins/filter/gemini.rb +1 -1
  34. data/plugins/filter/ignore.rb +1 -1
  35. data/plugins/filter/image.rb +1 -1
  36. data/plugins/filter/image_source.rb +20 -3
  37. data/plugins/filter/join.rb +4 -6
  38. data/plugins/filter/kimi.rb +216 -0
  39. data/plugins/filter/limit.rb +57 -0
  40. data/plugins/filter/open_ai.rb +1 -1
  41. data/plugins/filter/present.rb +75 -0
  42. data/plugins/filter/sakura_ai.rb +1 -1
  43. data/plugins/filter/sanitize.rb +1 -1
  44. data/plugins/filter/sort.rb +1 -1
  45. data/plugins/filter/tumblr_resize.rb +1 -1
  46. data/plugins/notify/ikachan.rb +1 -1
  47. data/plugins/provide/fluentd.rb +1 -1
  48. data/plugins/publish/amazon_s3.rb +9 -3
  49. data/plugins/publish/console.rb +1 -1
  50. data/plugins/publish/fluentd.rb +1 -1
  51. data/plugins/publish/hatena_bookmark.rb +1 -1
  52. data/plugins/publish/markdown.rb +1 -1
  53. data/plugins/publish/memcached.rb +1 -1
  54. data/plugins/store/digest.rb +1 -1
  55. data/plugins/store/file.rb +11 -3
  56. data/plugins/store/full_text.rb +9 -13
  57. data/plugins/store/permalink.rb +1 -1
  58. data/plugins/subscription/feed.rb +1 -1
  59. data/plugins/subscription/link.rb +1 -1
  60. data/plugins/subscription/text.rb +13 -4
  61. data/plugins/subscription/tumblr.rb +1 -1
  62. data/plugins/subscription/xml.rb +1 -1
  63. metadata +6 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5960b7f0e475aa9c6f3849866dd09a2a81181c38c6ecc45debb166b7afb59883
4
- data.tar.gz: eb0930479acc0b4c0248642c253f42e7c2a772ecc21f811a33cdd4cc4840e12a
3
+ metadata.gz: 98774a790d503f61900aa6ce06b982076eb13ed89e748fe6c08747592de0cafa
4
+ data.tar.gz: ac513ed3b38cbf05a872cffc35acefdf0a89a57adcbbe6d03f53c75958bd1b14
5
5
  SHA512:
6
- metadata.gz: 257008bf08a5a90bd2e634d8019a9b5bc614866bbc68c838e7b3f4cb89e26ff1fbaa402e3a05be4865db1bc1b6d63544b98648bd38ba44fbf63f4e6f53824682
7
- data.tar.gz: 991ebb59aa6f2ff2a3c785078179b8c44bf429c28934d6e7bc8f1f459d799a41bd6691cddd9e6adc9f34f2d5f38b8a60545924421eb9665df4f70a8085d6d66b
6
+ metadata.gz: 7ec9eb37f4335d6fc32c02979c9ce8f549df6fa6edc6b76530515f9b169abfb3e77bc5f39a5bbf945a5e1d769b2cf8e8cc7019315f522b9fb793be52473c5be8
7
+ data.tar.gz: 5c2f2d68407d65d1749c415532d0300788ca003edeb7d9aff22da2b49ce32d4455d1cee63702bd07a7671dd4b4262be74b690db9d073e8287a14a0adab45b4a3
data/README.md CHANGED
@@ -35,7 +35,7 @@ Fluentd, or writes them to a database. Write your own plugin and it composes
35
35
  with all the others.
36
36
 
37
37
  **[Follow the Quick Start](doc/QUICKSTART.md)** to install the gem, write a
38
- Recipe that watches four public index pages, install what that Recipe needs, and
38
+ Recipe that watches public index pages, install what that Recipe needs, and
39
39
  produce Markdown from the articles they list.
40
40
 
41
41
  ---
@@ -59,7 +59,8 @@ produce Markdown from the articles they list.
59
59
  15. [Documents](#15-documents)
60
60
  16. [Versioning](#16-versioning)
61
61
  17. [Name](#17-name)
62
- 18. [License](#18-license)
62
+ 18. [Primary Branch](#18-primary-branch)
63
+ 19. [License](#19-license)
63
64
 
64
65
  ---
65
66
 
@@ -78,6 +79,18 @@ them — takes it as input without a parser or an API. That is the general case,
78
79
  and it needs no account anywhere; the plugins that publish to a service are for
79
80
  when a particular service is the point.
80
81
 
82
+ Automatic Ruby is neither host infrastructure nor a purpose-built
83
+ application. It is a general-purpose composition framework: a small mechanism
84
+ for assembling independent steps into a straight-line job. Its generality
85
+ comes from how many jobs fit that composition model, not from growing the
86
+ framework until every kind of workflow fits inside it.
87
+
88
+ When one concrete purpose needs branching, transactional orchestration,
89
+ multi-user state, permissions, a strongly coupled domain model, or another
90
+ responsibility that does not fit a short plugin pipeline naturally, a
91
+ purpose-built application is usually the better design. Automatic Ruby is
92
+ not made more general by absorbing that complexity into its core.
93
+
81
94
  Automatic Ruby exists so that those jobs are assembled instead. It contributes
82
95
  exactly three things:
83
96
 
@@ -86,8 +99,10 @@ exactly three things:
86
99
  over,
87
100
  - **a loader** that finds a step by name, so that a Recipe can name it.
88
101
 
89
- Everything else is a plugin. The framework is under seven hundred lines of Ruby
90
- and is meant to stay that size.
102
+ Everything else is a plugin. The framework is intentionally kept small; its
103
+ responsibilities and architectural boundary are defined in
104
+ [`doc/BASIC_DESIGN.md`](doc/BASIC_DESIGN.md) and
105
+ [`doc/POLICY.md`](doc/POLICY.md).
91
106
 
92
107
  It is one person's tooling, run unattended from `cron`, against their own
93
108
  accounts and their own files. It is not a service, and there is no notion of a
@@ -103,8 +118,8 @@ a plugin set every part of which still has somewhere to talk to. See
103
118
 
104
119
  - **Recipes in YAML.** A job is a file, not a program. No Ruby is written to
105
120
  wire a pipeline together.
106
- - **41 plugins** across seven categories: subscribe, custom feed, filter,
107
- store, provide, notify, publish — and every one of them has a current use.
121
+ - **Plugins organized by role.** Subscribe, custom feed, filter, store, provide,
122
+ notify and publish plugins compose through the same pipeline contract.
108
123
  - **Markdown out of the box.** `PublishMarkdown` writes the result as a plain
109
124
  Markdown document, to a file or to standard output, with no service and no
110
125
  credential behind it. It is the natural end of a new Recipe.
@@ -118,9 +133,9 @@ a plugin set every part of which still has somewhere to talk to. See
118
133
  - **Retry and interval** on everything that reaches the network, configured per
119
134
  plugin in the Recipe.
120
135
  - **A small installation.** A gem needed by one plugin is not a dependency of
121
- the framework: `gem install automatic` brings four pure-Ruby gems and the
122
- command, and installs neither an HTML parser nor a database — let alone an
123
- AWS SDK.
136
+ the framework: `gem install automatic` brings the framework's runtime
137
+ dependencies declared in `automatic.gemspec` and the command, and installs
138
+ neither an HTML parser nor a database — let alone an AWS SDK.
124
139
  - **No museum.** Every plugin is classified, with its reason, in
125
140
  [`doc/PLUGINS.md`](doc/PLUGINS.md). Nothing dead is stubbed into looking
126
141
  alive, and an integration whose service has gone is removed rather than
@@ -159,6 +174,11 @@ That is the whole of the framework's behaviour. The value passed along — the
159
174
  *pipeline* — is an array of feed objects, and because every plugin takes and
160
175
  returns that one shape, any plugin composes with any other.
161
176
 
177
+ This composability is an architectural invariant, not an optimization
178
+ preference. Keeping the core small, keeping plugin responsibilities
179
+ independent and keeping one pipeline shape are what make Automatic Ruby this
180
+ framework rather than a collection of hard-coded applications.
181
+
162
182
  The pipeline normally **narrows**: subscription plugins produce, filters and
163
183
  stores reduce, publishers consume. Reading a Recipe top to bottom reads the
164
184
  data flow.
@@ -167,7 +187,8 @@ The full account is [`doc/BASIC_DESIGN.md`](doc/BASIC_DESIGN.md).
167
187
 
168
188
  ## 4. Supported environment
169
189
 
170
- - **Ruby 3.3 through 4.0.** CI validates 3.3, 3.4 and 4.0.
190
+ - **Ruby 3.3 through 4.0.** The continuously validated versions are the matrix
191
+ in [`.github/workflows/ci.yml`](.github/workflows/ci.yml).
171
192
  - A Unix-like system. GNU/Linux and macOS are what it is used on. Windows is not
172
193
  supported.
173
194
  - A compiler only if you install an optional plugin gem that builds from source
@@ -182,21 +203,25 @@ Two statements, and they are not the same one:
182
203
  - **Supported range.** The code is written for Ruby 3.3 through 4.0, using APIs
183
204
  the whole range shares. `required_ruby_version` is `>= 3.3.0` and has no upper
184
205
  bound, so a Ruby newer than the matrix is permitted rather than refused.
185
- - **Continuously validated versions.** CI runs the ends of the range and the
186
- release in the middle — 3.3, 3.4 and 4.0 — rather than every intermediate
187
- release. A version's absence from the matrix means it is not verified on every
188
- commit; it does not mean it is expected to fail.
206
+ - **Continuously validated versions.** The authoritative set is the matrix in
207
+ [`.github/workflows/ci.yml`](.github/workflows/ci.yml), which represents the
208
+ supported range rather than enumerating every intermediate release. A
209
+ version's absence from the matrix means it is not verified on every commit;
210
+ it does not mean it is expected to fail.
189
211
 
190
212
  ## 5. Installation
191
213
 
192
214
  ### From RubyGems
193
215
 
216
+ The released gem is available as [automatic on RubyGems](https://rubygems.org/gems/automatic).
217
+
194
218
  ```sh
195
219
  gem install automatic
196
220
  automatic --version
197
221
  ```
198
222
 
199
- That installs the framework, the command and four pure-Ruby dependencies.
223
+ That installs the framework, the command and the runtime dependencies
224
+ declared in `automatic.gemspec`.
200
225
  A gem that only one plugin needs is not among them: install it when you use
201
226
  that plugin, with `gem install nokogiri` or `gem install activerecord sqlite3`.
202
227
  [`doc/DEPLOYMENT.md`](doc/DEPLOYMENT.md) lists which plugin needs which.
@@ -204,8 +229,7 @@ that plugin, with `gem install nokogiri` or `gem install activerecord sqlite3`.
204
229
  ### From a checkout
205
230
 
206
231
  Use a checkout to try the current development version, change the source,
207
- develop a plugin or verify changes before a release. There are three ways to
208
- set one up; start with the first.
232
+ develop a plugin or verify changes before a release. The supported checkout setups are shown below; start with the minimal setup.
209
233
 
210
234
  ```sh
211
235
  git clone https://github.com/id774/automaticruby.git
@@ -245,8 +269,9 @@ a Recipe taken step by step through choosing its groups are in
245
269
  ## 6. Quick start
246
270
 
247
271
  The complete first-run guide is [`doc/QUICKSTART.md`](doc/QUICKSTART.md): it
248
- writes one Recipe that reads four public index pages, installs what that Recipe
249
- needs, and leaves the new articles in a Markdown document.
272
+ writes one Recipe that reads the public index pages listed by that guide,
273
+ installs what that Recipe needs, and leaves the new articles in a Markdown
274
+ document.
250
275
 
251
276
  ```sh
252
277
  automatic scaffold
@@ -263,7 +288,9 @@ nothing but the framework and what `gem install automatic` brought.
263
288
  `feed2console.yml` beside it is the same pipeline printing to the terminal. Read
264
289
  the file, `grep` it, put it in a repository, or hand it to whatever reads text
265
290
  next. A Recipe that names a plugin with an optional gem installs that gem first,
266
- which is step 4 of the Quick Start and the habit worth learning early.
291
+ which is covered by the "Install what the Recipe needs" section of
292
+ [`doc/QUICKSTART.md`](doc/QUICKSTART.md) and is the habit worth learning
293
+ early.
267
294
 
268
295
  To check the framework without any network, write this instead:
269
296
 
@@ -316,7 +343,7 @@ plugins: # required
316
343
  - `global.log.level` is the only framework setting. `global.timezone` and
317
344
  `global.cache` appear in old Recipes and are read by nothing.
318
345
 
319
- Two conventions worth knowing before writing one:
346
+ Conventions worth knowing before writing one:
320
347
 
321
348
  - **Put a store plugin in front of anything with an effect.** `StorePermalink`
322
349
  records what has been seen and passes on only what has not. It is what makes a
@@ -375,24 +402,21 @@ like a shipped plugin replaces it.
375
402
 
376
403
  ### Which plugins still work
377
404
 
378
- 41 plugins ship with the gem. Every one is classified in
379
- [`doc/PLUGINS.md`](doc/PLUGINS.md) section 6, with its settings and the reason
380
- for its status:
381
-
382
- | Status | Count | Meaning |
383
- | --- | --- | --- |
384
- | **Supported** | 26 | Works on the supported Rubies with current dependencies |
385
- | **Supported (external)** | 14 | Works, but needs something you provide: a service, a command, a credential, a data file |
386
- | **Needs rework** | 1 | The service exists; this plugin speaks a replaced interface |
405
+ The complete shipped-plugin catalogue and the current status of each plugin
406
+ are maintained in
407
+ [`doc/PLUGINS.md`](doc/PLUGINS.md#6-the-plugins).
408
+ The status vocabulary and its meaning are defined in
409
+ [Reading the catalogue](doc/PLUGINS.md#5-reading-the-catalogue), and removed
410
+ integrations and the reasons for their removal are recorded in
411
+ [Plugins that were removed](doc/PLUGINS.md#8-plugins-that-were-removed).
387
412
 
388
- Eleven plugins were removed in this release rather than kept as history: each
389
- talked to a service that has shut down, or through an API that has been
390
- withdrawn with no replacement. They are listed with their reasons in
391
- [`doc/PLUGINS.md`](doc/PLUGINS.md) section 8, and Git history holds the code.
392
- A Recipe naming one of them now fails at load, before anything runs.
413
+ This README intentionally does not repeat current plugin totals, per-status
414
+ totals, or the current membership of a status. Adding, removing, or
415
+ reclassifying a plugin changes the canonical catalogue rather than a
416
+ synchronized summary here.
393
417
 
394
- Restoring the one in **Needs rework** — `PublishHatenaBookmark` — is
395
- self-contained work and a good first contribution.
418
+ A plugin classified as **Needs rework** in the catalogue is a
419
+ self-contained contribution candidate.
396
420
 
397
421
  No plugin here is stubbed, mocked or simulated to make a test pass. Where a
398
422
  plugin's gem is not installed its spec is skipped and says which gem is
@@ -431,8 +455,8 @@ automatic --version
431
455
  | `opmlparser <path>` | Print the feed URLs in an OPML file. |
432
456
  | `log <level> <message>` | Emit one line in the framework's log format. |
433
457
 
434
- The middle five answer "will this work as a Recipe input?" before you write the
435
- Recipe:
458
+ The discovery and parsing subcommands help answer "will this work as a Recipe
459
+ input?" before you write the Recipe:
436
460
 
437
461
  ```sh
438
462
  automatic autodiscovery https://example.com/
@@ -456,8 +480,9 @@ There is no configuration file besides the Recipe. Every setting a job needs is
456
480
  in the Recipe that defines the job, which is what makes a Recipe portable
457
481
  between machines.
458
482
 
459
- **Framework settings** — one, `global.log.level`, with the values `info`,
460
- `warn`, `error` and `none`.
483
+ **Framework setting:** `global.log.level`, with the values `info`, `warn`,
484
+ `error` and `none`. Its Recipe-level contract is specified in
485
+ [`doc/PLUGINS.md`](doc/PLUGINS.md#24-global).
461
486
 
462
487
  **Plugin settings** — the `config` mapping of a plugin entry, passed to that
463
488
  plugin and read by nothing else. Established names: `retry` for an attempt
@@ -558,8 +583,8 @@ bundle exec rake
558
583
  bundle exec bin/automatic -c config/feed2console.yml
559
584
  ```
560
585
 
561
- Contributions are welcome — a new plugin, or reviving the one that needs
562
- rework, most of all.
586
+ Contributions are welcome — a new plugin, or restoring a plugin currently
587
+ classified as **Needs rework** in the canonical catalogue, most of all.
563
588
 
564
589
  1. Fork the repository.
565
590
  2. Write the change, with a spec that reaches no network.
@@ -572,7 +597,7 @@ judged by: the direction of dependency, where a new capability belongs, how
572
597
  dependencies are added, how the documents divide, and how a version history
573
598
  entry is written.
574
599
 
575
- Two rules worth knowing before you start:
600
+ Rules worth knowing before you start:
576
601
 
577
602
  - **A gem needed by one plugin is not a dependency of the framework.** Require
578
603
  it at the top of the plugin's own file.
@@ -658,6 +683,9 @@ February 2012.
658
683
  26.08.1 a release correcting 26.08 in the same month
659
684
  ```
660
685
 
686
+ A patch release may correct an earlier release in the same month, but a
687
+ versioned release is never made twice on the same calendar date.
688
+
661
689
  The number carries no compatibility meaning: a month is not a major version. A
662
690
  change that affects an existing Recipe is stated as such in its
663
691
  [`doc/VERSIONS`](doc/VERSIONS) entry.
@@ -681,7 +709,13 @@ Plagger, and I wanted the name to put two things up front: **automatic**
681
709
  processing, and doing it in **Ruby** rather than Perl. *Automatic Ruby* said
682
710
  both, sounded natural enough, and was easy to remember. That was enough.
683
711
 
684
- ## 18. License
712
+ ## 18. Primary Branch
713
+
714
+ This repository uses `master` as its primary branch name.
715
+
716
+ The name is used solely as a technical identifier, following the long-standing convention historically used by Git. It does not express or imply any association with racism, slavery, discrimination, or any political or social ideology.
717
+
718
+ ## 19. License
685
719
 
686
720
  Automatic Ruby is dual-licensed under the
687
721
  [GNU General Public License, Version 3](https://www.gnu.org/licenses/gpl-3.0.html)
@@ -694,5 +728,5 @@ See [`doc/LICENSE.md`](doc/LICENSE.md), [`doc/COPYING`](doc/COPYING) and
694
728
 
695
729
  Copyright (c) 2012-2026 Automatic Ruby Developers.
696
730
 
697
- Project created by [id774](http://id774.net). Contributors are listed in
731
+ Project created by [id774](https://id774.net). Contributors are listed in
698
732
  [`doc/AUTHORS`](doc/AUTHORS).
data/VERSION CHANGED
@@ -1 +1 @@
1
- 26.08
1
+ 26.09