pricing_plans 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6909ac57e070c2504657a4fd03d4be65c320dfde3a06458e5daa36ee81ba953a
4
- data.tar.gz: ff00984bc91cac2e156af5909434e6fed135c5feb06d8047187edcb81d2e1a9a
3
+ metadata.gz: c1822c0e4c0d410596c9640baec0d6546256db8ea402744fbb4d47917e39fd88
4
+ data.tar.gz: b0ae7556f2181fd2a99df2ddb9f4a9cc7f9ab3b7298346fa260d6e3b7c059d70
5
5
  SHA512:
6
- metadata.gz: d8dc596158a482b5d466a3ad8bc2d6bbcced8639da88241a65b201acff9a9cbd5080aa6cfd6e0f317c8f558219973d63847cf9c0d3d9cca81b4d6f020740bb7c
7
- data.tar.gz: 5827c8e721f641ed179c6bd42ade5c18c30a299099ae21e8af8eac285d886b311a896bba43636ed7fb2bdf698531839d471a66d4a94676787741b458afe48f18
6
+ metadata.gz: 121f9fd26e721c59dbf0e7a8ec67647792df985343224f4087538b9607571bfa1f1cc74e23532caad7ae60db2049436540b490fedef660458dbd85beda795365
7
+ data.tar.gz: e42d52966e3f7ae4c32b90e766fbb58e50d1c7c3489b3a5f0176ffac7b34613f3907d89d050d68ca9d2cd9a8bfcf71779d614537314d9ac28faf698eef79af2a
data/CHANGELOG.md CHANGED
@@ -5,79 +5,11 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [Unreleased]
8
+ ## [0.1.1] - 2025-12-25
9
9
 
10
- ## [0.1.0] - 2025-08-07
10
+ - Add support for Rails 8+
11
+ - Fix a bug where `throw :abort` was causing `UncaughtThrowError` exceptions in controller guards, and instead return `false` from `before_action` callbacks to halt the filter chain, rather than using the uncaught throw
11
12
 
12
- ### Added
13
+ ## [0.1.0] - 2025-08-19
13
14
 
14
- **Core Features**
15
- - Plan catalog configuration system with English-first DSL
16
- - Feature flags (boolean allows/disallows)
17
- - Persistent caps (max concurrent resources like projects, seats)
18
- - Per-period discrete allowances (e.g., "3 custom models/month")
19
- - Grace period enforcement with configurable behaviors
20
- - Event system for warning/grace/block notifications
21
-
22
- **Configuration & DSL**
23
- - `PricingPlans.configure` block for one-file configuration
24
- - Plan definition with name, description, bullets, pricing
25
- - `Integer#max` refinement for clean DSL (`5.max`)
26
- - Support for Stripe price IDs and manual pricing
27
- - Flexible period cycles (billing, calendar month/week/day, custom)
28
-
29
- **Database & Models**
30
- - Three-table schema for enforcement states, usage counters, assignments
31
- - `EnforcementState` model for grace period tracking with row-level locking
32
- - `Usage` model for per-period counters with atomic upserts
33
- - `Assignment` model for manual plan overrides
34
-
35
- **Controller Integration**
36
- - `require_plan_limit!` guard returning rich Result objects
37
- - `require_feature!` guard with FeatureDenied exception
38
- - Automatic grace period management and event emission
39
- - Race-safe limit checking with retries
40
-
41
- **Model Integration**
42
- - `Limitable` mixin for ActiveRecord models
43
- - `limited_by` macro for automatic usage tracking
44
- - Real-time persistent caps (no counter caches needed)
45
- - Automatic per-period counter increments
46
-
47
- **View Helpers & UI**
48
- - Complete pricing table rendering
49
- - Usage meters with progress bars
50
- - Limit banners with warnings/grace/blocked states
51
- - Plan information helpers (current plan, feature checks)
52
-
53
- **Pay Integration**
54
- - Automatic plan resolution from Stripe subscriptions
55
- - Support for trial, grace, and active subscription states
56
- - Price ID to plan mapping
57
- - Billing cycle anchor integration for periods
58
-
59
- **usage_credits Integration**
60
- - Credit inclusion display in pricing tables
61
- - Boot-time linting to prevent limit/credit collisions
62
- - Operation validation against usage_credits registry
63
- - Clean separation of concerns (credits vs discrete limits)
64
-
65
- **Generators**
66
- - Install generator with migrations and initializer template
67
- - Pricing generator with views, controller, and CSS
68
- - Comprehensive Tailwind-friendly styling
69
-
70
- **Architecture & Performance**
71
- - Rails Engine for seamless integration
72
- - Autoloading with proper namespacing
73
- - Row-level locking for race condition prevention
74
- - Efficient query patterns with proper indexing
75
- - Memoization and caching where appropriate
76
-
77
- ### Technical Details
78
-
79
- - Ruby 3.2+ requirement
80
- - Rails 7.1+ requirement (ActiveRecord, ActiveSupport)
81
- - PostgreSQL optimized (with fallbacks for other databases)
82
- - Comprehensive error handling and validation
83
- - Thread-safe implementation throughout
15
+ Initial release
data/CLAUDE.md ADDED
@@ -0,0 +1 @@
1
+ When reviewing code and PRs inside GitHub, just outline the main findings in 4-5 bullet points, and then give your recommendation (approve / fix stuff / close, etc.) DO NOT be pedantic, DO NOT overengineer, DO NOT write long detailed reviews. Always be on the lookout for supply chain attacks. You're just helping a human analyze code changes and review PRs so nothing harmful or bugs get in the codebase inadvertently. Be pragmatic, concise, and to the point.
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # 💵 `pricing_plans` - Define and enforce pricing plan limits in your Rails app (SaaS entitlements)
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/pricing_plans.svg)](https://badge.fury.io/rb/pricing_plans)
3
+ [![Gem Version](https://badge.fury.io/rb/pricing_plans.svg?x=1)](https://badge.fury.io/rb/pricing_plans)
4
4
 
5
5
  Enforce pricing plan limits with one-liners that read like plain English. Avoid scattering and entangling pricing logic everywhere in your Rails SaaS.
6
6
 
@@ -133,9 +133,8 @@ module PricingPlans
133
133
  end
134
134
  by = options.key?(:by) ? options[:by] : 1
135
135
  allow_system_override = !!options[:allow_system_override]
136
- redirect_path = options[:redirect_to]
137
- enforce_plan_limit!(limit_key, plan_owner: owner, by: by, allow_system_override: allow_system_override, redirect_to: redirect_path)
138
- return true
136
+ redirect_path = options[:redirect_to]
137
+ return enforce_plan_limit!(limit_key, plan_owner: owner, by: by, allow_system_override: allow_system_override, redirect_to: redirect_path)
139
138
  elsif method_name.to_s =~ /^enforce_(.+)!$/
140
139
  feature_key = Regexp.last_match(1).to_sym
141
140
  options = args.first.is_a?(Hash) ? args.first : {}
@@ -230,7 +229,7 @@ module PricingPlans
230
229
  end
231
230
  end
232
231
 
233
- # Rails-y controller ergonomics: enforce, set flash/redirect, and abort the callback chain when blocked.
232
+ # Rails-y controller ergonomics: enforce limits and set flash/redirect when blocked.
234
233
  # Defaults:
235
234
  # - On blocked: redirect_to pricing_path (if available) with alert; else render 403 JSON.
236
235
  # - On grace/warning: set flash[:warning] with the human message.
@@ -264,8 +263,6 @@ module PricingPlans
264
263
  respond_to?(:request) && request&.format&.json? ? render(json: { error: result.message }, status: :forbidden) : render(plain: result.message, status: :forbidden)
265
264
  end
266
265
  end
267
- # Stop the filter chain (for before_action ergonomics)
268
- throw :abort
269
266
  return false
270
267
  elsif result.warning? || result.grace?
271
268
  if respond_to?(:flash) && flash.respond_to?(:[]=)
@@ -277,7 +274,7 @@ module PricingPlans
277
274
  end
278
275
 
279
276
  # Controller-focused sugar: run a block within the plan limit context.
280
- # - If blocked: performs the same redirect/render semantics as enforce_plan_limit! and aborts the callback chain.
277
+ # - If blocked: performs the same redirect/render semantics as enforce_plan_limit! and returns false.
281
278
  # - If warning/grace: sets flash[:warning] and yields the result.
282
279
  # - If within: simply yields the result.
283
280
  # Returns the PricingPlans::Result in all cases where execution continues.
@@ -314,7 +311,7 @@ module PricingPlans
314
311
  respond_to?(:request) && request&.format&.json? ? render(json: { error: result.message }, status: :forbidden) : render(plain: result.message, status: :forbidden)
315
312
  end
316
313
  end
317
- throw :abort
314
+ return false
318
315
  else
319
316
  if (result.warning? || result.grace?) && respond_to?(:flash) && flash.respond_to?(:[]=)
320
317
  flash[:warning] ||= result.message
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PricingPlans
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
metadata CHANGED
@@ -1,54 +1,54 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pricing_plans
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - rameerez
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-08-19 00:00:00.000000000 Z
10
+ date: 2025-12-26 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: activerecord
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
- - - "~>"
17
- - !ruby/object:Gem::Version
18
- version: '7.1'
19
16
  - - ">="
20
17
  - !ruby/object:Gem::Version
21
18
  version: 7.1.0
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '9.0'
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
- - - "~>"
27
- - !ruby/object:Gem::Version
28
- version: '7.1'
29
26
  - - ">="
30
27
  - !ruby/object:Gem::Version
31
28
  version: 7.1.0
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '9.0'
32
32
  - !ruby/object:Gem::Dependency
33
33
  name: activesupport
34
34
  requirement: !ruby/object:Gem::Requirement
35
35
  requirements:
36
- - - "~>"
37
- - !ruby/object:Gem::Version
38
- version: '7.1'
39
36
  - - ">="
40
37
  - !ruby/object:Gem::Version
41
38
  version: 7.1.0
39
+ - - "<"
40
+ - !ruby/object:Gem::Version
41
+ version: '9.0'
42
42
  type: :runtime
43
43
  prerelease: false
44
44
  version_requirements: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - "~>"
47
- - !ruby/object:Gem::Version
48
- version: '7.1'
49
46
  - - ">="
50
47
  - !ruby/object:Gem::Version
51
48
  version: 7.1.0
49
+ - - "<"
50
+ - !ruby/object:Gem::Version
51
+ version: '9.0'
52
52
  - !ruby/object:Gem::Dependency
53
53
  name: bundler
54
54
  requirement: !ruby/object:Gem::Requirement
@@ -162,6 +162,7 @@ files:
162
162
  - ".claude/settings.local.json"
163
163
  - ".rubocop.yml"
164
164
  - CHANGELOG.md
165
+ - CLAUDE.md
165
166
  - LICENSE.txt
166
167
  - README.md
167
168
  - Rakefile