easyop 0.1.0 → 0.1.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e1949724cfdf1045f5b0ab6f013187b395f3baaf96b357a6367c894b251ce1e2
4
- data.tar.gz: d22d453c480ce21caf923195c36f984135e488454bdb939131cc0e896088017d
3
+ metadata.gz: 9157dccd94c6847b4b83c01404b64d48ffe54f1f6f51a99e0263bb718a2acdc4
4
+ data.tar.gz: 62bbaa697722e2b0d1979bc5a20839fb9dc765ee22d989f404591129a8a72c01
5
5
  SHA512:
6
- metadata.gz: b956452863277b0218420ee73ca45eb9e28b449441ac2bc4458dcb5880cb95630ff5a5395ced570c50df1e2f98523b782dc5f39befc574834d13d739daf917be
7
- data.tar.gz: 700f88243a8ba2a3add1c394c97ffc2d3e09e5a10ca157a1c4fcd5256fefc327bc04480ee5ddda8c329d3ff787acfb0321b33b219ca9ba78cc858b8c7ab4ea67
6
+ metadata.gz: 52fc250d99c11808462344afb74603081aa2dd35ca4f4d16ec263d19b3c098bba77ddcdda7963793483a9bfc0b04bd2cf63a70700c9756e0fb6b4610229ecc9f
7
+ data.tar.gz: 778348d6dc863bdda5816a32738ae2262c3948eb3711090b0a4412bc0678a9dc9b7c87e48cd937c3f1842e492f5be787c252c42f8ae9955191794cc9200dfc1e
data/CHANGELOG.md CHANGED
@@ -7,6 +7,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.1.2] — 2026-04-13
11
+
12
+ ### Added
13
+
14
+ - **`Plugins::Async` — `queue` DSL** — a new `queue` class method for declaring the default queue directly on an operation class (or a shared base class). This lets subclasses override the queue set at plugin install time without re-declaring the plugin:
15
+
16
+ ```ruby
17
+ class Weather::BaseOperation < ApplicationOperation
18
+ queue :weather # all Weather ops use the "weather" queue
19
+ end
20
+
21
+ class Weather::FetchForecast < Weather::BaseOperation
22
+ # inherits queue :weather automatically
23
+ end
24
+
25
+ class Weather::CleanupExpiredDays < Weather::BaseOperation
26
+ queue :low_priority # override just for this class
27
+ end
28
+ ```
29
+
30
+ Accepts both `Symbol` and `String`. The setting is inherited by subclasses and can be overridden at any level of the hierarchy.
31
+
32
+ ## [0.1.1] — 2026-04-01
33
+
34
+ ### Fixed
35
+
36
+ - **`Plugins::Recording`** — operations executed as steps inside a `Flow` were not recorded on failure. Flows run each step with `raise_on_failure: true`, causing `Ctx::Failure` to propagate and skip the `.tap` block used to persist the log entry. Fixed by moving the persistence call into an `ensure` block so every execution — successful or failed — is always recorded.
37
+
10
38
  ## [0.1.0] — 2026-04-01
11
39
 
12
40
  ### Added
@@ -37,5 +65,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
37
65
  - `examples/easyop_test_app/` — full Rails 8 blog application demonstrating all features in real-world code
38
66
  - `examples/usage.rb` — 13 runnable plain-Ruby examples
39
67
 
40
- [Unreleased]: https://github.com/pniemczyk/easyop/compare/v0.1.0...HEAD
68
+ [Unreleased]: https://github.com/pniemczyk/easyop/compare/v0.1.2...HEAD
69
+ [0.1.2]: https://github.com/pniemczyk/easyop/compare/v0.1.1...v0.1.2
70
+ [0.1.1]: https://github.com/pniemczyk/easyop/compare/v0.1.0...v0.1.1
41
71
  [0.1.0]: https://github.com/pniemczyk/easyop/releases/tag/v0.1.0
data/README.md CHANGED
@@ -672,6 +672,20 @@ Newsletter::SendBroadcast.call_async(attrs, wait_until: Date.tomorrow.noon)
672
672
  Newsletter::SendBroadcast.call_async(attrs, queue: "low_priority")
673
673
  ```
674
674
 
675
+ **`queue` DSL** — declare the default queue directly on a class (or a shared base class) instead of at plugin install time:
676
+
677
+ ```ruby
678
+ class Weather::BaseOperation < ApplicationOperation
679
+ queue :weather # all Weather ops use the "weather" queue by default
680
+ end
681
+
682
+ class Weather::CleanupExpiredDays < Weather::BaseOperation
683
+ queue :low_priority # override just for this class
684
+ end
685
+ ```
686
+
687
+ The `queue` setting is inherited by subclasses and can be overridden at any level. Accepts `Symbol` or `String`. A per-call `queue:` argument to `.call_async` always takes precedence.
688
+
675
689
  **ActiveRecord objects** are serialized by `(class, id)` and re-fetched in the job:
676
690
 
677
691
  ```ruby
@@ -983,15 +997,13 @@ ProcessCheckout.prepare
983
997
  ruby examples/usage.rb
984
998
  ```
985
999
 
986
- ## Example Rails App
1000
+ ## Example Rails Apps
987
1001
 
988
- A full Rails 8 blog application demonstrating every EasyOp feature in real-world code lives in `/examples/easyop_test_app/`. It is **not included in the gem** — only in the repository.
1002
+ Two full Rails 8 applications live in `/examples/`. Neither is included in the gem — repository only.
989
1003
 
990
- ```
991
- /examples/easyop_test_app/
992
- ```
1004
+ ### Blog App — `easyop_test_app`
993
1005
 
994
- The app covers:
1006
+ A blog + newsletter app demonstrating the full EasyOp feature set.
995
1007
 
996
1008
  | Feature | Where to look |
997
1009
  |---|---|
@@ -1006,10 +1018,8 @@ The app covers:
1006
1018
  | Transactional plugin | `ApplicationOperation` → all DB ops wrapped in transactions |
1007
1019
  | Rails controller integration | `app/controllers/articles_controller.rb`, `transfers_controller.rb` |
1008
1020
 
1009
- **Running the example app:**
1010
-
1011
1021
  ```bash
1012
- cd /examples/easyop_test_app
1022
+ cd examples/easyop_test_app
1013
1023
  bundle install
1014
1024
  bin/rails db:create db:migrate db:seed
1015
1025
  bin/rails server -p 3002
@@ -1017,6 +1027,31 @@ bin/rails server -p 3002
1017
1027
 
1018
1028
  Seed accounts: `alice@example.com` / `password123` (500 credits), `bob`, `carol`, `dave` (0 credits — tests insufficient-funds error).
1019
1029
 
1030
+ ### TicketFlow — `ticketflow`
1031
+
1032
+ A full event ticket-selling platform with modern Tailwind UI and admin panel. Every operation is powered by EasyOp.
1033
+
1034
+ | Feature | Where to look |
1035
+ |---|---|
1036
+ | Multi-step checkout Flow | `app/operations/flows/checkout.rb` — 6 chained operations |
1037
+ | `skip_if` (optional discount step) | `app/operations/orders/apply_discount.rb` |
1038
+ | Rollback on payment failure | `app/operations/orders/process_payment.rb#rollback` |
1039
+ | `prepare` + callbacks in controller | `app/controllers/checkouts_controller.rb` |
1040
+ | Recording plugin → operation logs | `app/operations/application_operation.rb` |
1041
+ | Admin metrics dashboard | `app/controllers/admin/dashboard_controller.rb` |
1042
+ | Admin order refund operation | `app/operations/admin/refund_order.rb` |
1043
+ | Virtual ticket generation | `app/operations/tickets/generate_tickets.rb` |
1044
+
1045
+ ```bash
1046
+ cd examples/ticketflow
1047
+ bundle install
1048
+ bin/rails db:create db:migrate db:seed
1049
+ bin/rails server -p 3001
1050
+ ```
1051
+
1052
+ Seed accounts: `admin@ticketflow.com` / `password123` (admin), `user@ticketflow.com` / `password123` (customer).
1053
+ Discount codes: `SAVE10` (10% off), `FLAT20` ($20 off), `VIP50` (50% off).
1054
+
1020
1055
  ## Running Specs
1021
1056
 
1022
1057
  ```
@@ -27,6 +27,18 @@ module Easyop
27
27
  end
28
28
 
29
29
  module ClassMethods
30
+ # Declares a non-default queue for this operation class and its subclasses.
31
+ #
32
+ # @example
33
+ # class Weather::BaseOperation < ApplicationOperation
34
+ # queue :weather
35
+ # end
36
+ #
37
+ # @param name [String, Symbol] queue name
38
+ def queue(name)
39
+ @_async_default_queue = name.to_s
40
+ end
41
+
30
42
  # Enqueue the operation as a background job.
31
43
  #
32
44
  # MyOp.call_async(email: "x@y.com")
@@ -71,7 +71,13 @@ module Easyop
71
71
  return super unless self.class.name # skip anonymous classes
72
72
 
73
73
  start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
74
- super.tap do
74
+ super
75
+ ensure
76
+ # Always record — including when raise_on_failure: true raises Ctx::Failure
77
+ # (e.g. when this operation is a step inside a Flow). Without the ensure
78
+ # branch the tap block would be skipped and failures inside flows would
79
+ # never be persisted.
80
+ if start
75
81
  ms = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) * 1000).round(2)
76
82
  _recording_persist!(ctx, model, ms)
77
83
  end
@@ -1,3 +1,3 @@
1
1
  module Easyop
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: easyop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pawel Niemczyk