Class: PricingPlans::Configuration
- Inherits:
-
Object
- Object
- PricingPlans::Configuration
- Includes:
- DSL
- Defined in:
- lib/pricing_plans/configuration.rb
Constant Summary collapse
- LEGACY_DEFAULT_PLAN_ASSIGNMENT_BEHAVIORS =
[:allow, :warn, :raise].freeze
Constants included from DSL
Instance Attribute Summary collapse
-
#auto_price_labels_from_processor ⇒ Object
Auto-fetch price labels from processor when possible (Stripe via stripe-ruby).
-
#controller_plan_owner_method ⇒ Object
readonly
Global controller ergonomics Optional global resolver for controller plan owner.
-
#controller_plan_owner_proc ⇒ Object
readonly
Global controller ergonomics Optional global resolver for controller plan owner.
-
#debug ⇒ Object
Debug mode - set to true to enable debug output.
-
#default_cta_text ⇒ Object
Optional ergonomics.
-
#default_cta_url ⇒ Object
Optional ergonomics.
-
#default_currency_symbol ⇒ Object
Default currency symbol when Stripe isn't available.
-
#default_plan ⇒ Object
Returns the value of attribute default_plan.
-
#downgrade_policy ⇒ Object
Optional downgrade policy hook for CTA ergonomics Signature: ->(from:, to:, plan_owner:) { [allowed_boolean, reason_string_or_nil] }.
-
#event_handlers ⇒ Object
readonly
Returns the value of attribute event_handlers.
-
#free_price_caption ⇒ Object
Optional free caption copy (UI copy holder).
-
#highlighted_plan ⇒ Object
Returns the value of attribute highlighted_plan.
-
#interval_default_for_ui ⇒ Object
Optional default interval for UI toggles.
-
#legacy_default_plan_assignment_behavior ⇒ Object
Controls what the deprecated assignment APIs do when they are asked to assign the configured default plan.
-
#message_builder ⇒ Object
Optional global message builder proc for human copy (i18n/hooks) Signature suggestion: (context:, **kwargs) -> string Contexts used: :over_limit, :grace, :feature_denied Example kwargs: limit_key:, current_usage:, limit_amount:, grace_ends_at:, feature_key:, plan_name:.
-
#period_cycle ⇒ Object
Returns the value of attribute period_cycle.
-
#plan_owner_class ⇒ Object
Returns the value of attribute plan_owner_class.
-
#plans ⇒ Object
readonly
Returns the value of attribute plans.
-
#price_cache ⇒ Object
Cache for Stripe prices.
-
#price_cache_ttl ⇒ Object
Seconds for cache TTL for Stripe lookups.
-
#price_components_resolver ⇒ Object
Semantic pricing components resolver hook: ->(plan, interval) { PriceComponents | nil }.
-
#price_label_resolver ⇒ Object
Optional: custom resolver for displaying price labels from processor Signature: ->(plan) { "$amount/mo" }.
-
#redirect_on_blocked_limit ⇒ Object
When a limit check blocks, controllers can redirect to a global default target.
Class Method Summary collapse
Instance Method Summary collapse
-
#controller_plan_owner(method_name = nil, &block) ⇒ Object
Global controller plan owner resolver API Usage: config.controller_plan_owner :current_organization # or config.controller_plan_owner { current_account }.
-
#initialize ⇒ Configuration
constructor
A new instance of Configuration.
-
#on_block(limit_key = nil) {|plan_owner, limit_key| ... } ⇒ Object
Register a callback for block events.
-
#on_grace_start(limit_key = nil) {|plan_owner, limit_key, grace_ends_at| ... } ⇒ Object
Register a callback for grace period start events.
-
#on_warning(limit_key = nil) {|plan_owner, limit_key, threshold| ... } ⇒ Object
Register a callback for warning events.
- #plan(key, &block) ⇒ Object
- #select_defaults_from_dsl! ⇒ Object
- #validate! ⇒ Object
- #validate_dsl_markers! ⇒ Object
Constructor Details
#initialize ⇒ Configuration
Returns a new instance of Configuration.
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/pricing_plans/configuration.rb', line 66 def initialize @plan_owner_class = nil @default_plan = nil @highlighted_plan = nil @period_cycle = :billing_cycle @legacy_default_plan_assignment_behavior = :warn @default_cta_text = nil @default_cta_url = nil @message_builder = nil @controller_plan_owner_method = nil @controller_plan_owner_proc = nil @redirect_on_blocked_limit = nil @price_label_resolver = nil @auto_price_labels_from_processor = true @price_components_resolver = nil @default_currency_symbol = "$" @price_cache = (defined?(Rails) && Rails.respond_to?(:cache)) ? Rails.cache : nil @price_cache_ttl = 600 # 10 minutes @free_price_caption = "Forever free" @interval_default_for_ui = :month @downgrade_policy = ->(from:, to:, plan_owner:) { [true, nil] } @debug = false @plans = {} @event_handlers = { warning: {}, grace_start: {}, block: {} } end |
Instance Attribute Details
#auto_price_labels_from_processor ⇒ Object
Auto-fetch price labels from processor when possible (Stripe via stripe-ruby)
48 49 50 |
# File 'lib/pricing_plans/configuration.rb', line 48 def auto_price_labels_from_processor @auto_price_labels_from_processor end |
#controller_plan_owner_method ⇒ Object (readonly)
Global controller ergonomics Optional global resolver for controller plan owner. Per-controller settings still win. Accepts:
- Symbol: a controller helper to call (e.g., :current_organization)
- Proc: instance-exec'd in the controller (self is the controller)
30 31 32 |
# File 'lib/pricing_plans/configuration.rb', line 30 def controller_plan_owner_method @controller_plan_owner_method end |
#controller_plan_owner_proc ⇒ Object (readonly)
Global controller ergonomics Optional global resolver for controller plan owner. Per-controller settings still win. Accepts:
- Symbol: a controller helper to call (e.g., :current_organization)
- Proc: instance-exec'd in the controller (self is the controller)
30 31 32 |
# File 'lib/pricing_plans/configuration.rb', line 30 def controller_plan_owner_proc @controller_plan_owner_proc end |
#debug ⇒ Object
Debug mode - set to true to enable debug output
24 25 26 |
# File 'lib/pricing_plans/configuration.rb', line 24 def debug @debug end |
#default_cta_text ⇒ Object
Optional ergonomics
22 23 24 |
# File 'lib/pricing_plans/configuration.rb', line 22 def default_cta_text @default_cta_text end |
#default_cta_url ⇒ Object
Optional ergonomics
22 23 24 |
# File 'lib/pricing_plans/configuration.rb', line 22 def default_cta_url @default_cta_url end |
#default_currency_symbol ⇒ Object
Default currency symbol when Stripe isn't available
52 53 54 |
# File 'lib/pricing_plans/configuration.rb', line 52 def default_currency_symbol @default_currency_symbol end |
#default_plan ⇒ Object
Returns the value of attribute default_plan.
16 17 18 |
# File 'lib/pricing_plans/configuration.rb', line 16 def default_plan @default_plan end |
#downgrade_policy ⇒ Object
Optional downgrade policy hook for CTA ergonomics Signature: ->(from:, to:, plan_owner:) { [allowed_boolean, reason_string_or_nil] }
63 64 65 |
# File 'lib/pricing_plans/configuration.rb', line 63 def downgrade_policy @downgrade_policy end |
#event_handlers ⇒ Object (readonly)
Returns the value of attribute event_handlers.
64 65 66 |
# File 'lib/pricing_plans/configuration.rb', line 64 def event_handlers @event_handlers end |
#free_price_caption ⇒ Object
Optional free caption copy (UI copy holder)
58 59 60 |
# File 'lib/pricing_plans/configuration.rb', line 58 def free_price_caption @free_price_caption end |
#highlighted_plan ⇒ Object
Returns the value of attribute highlighted_plan.
16 17 18 |
# File 'lib/pricing_plans/configuration.rb', line 16 def highlighted_plan @highlighted_plan end |
#interval_default_for_ui ⇒ Object
Optional default interval for UI toggles
60 61 62 |
# File 'lib/pricing_plans/configuration.rb', line 60 def interval_default_for_ui @interval_default_for_ui end |
#legacy_default_plan_assignment_behavior ⇒ Object
Controls what the deprecated assignment APIs do when they are asked to assign the configured default plan. Explicit override APIs are never affected because their names already communicate the caller's intent.
20 21 22 |
# File 'lib/pricing_plans/configuration.rb', line 20 def legacy_default_plan_assignment_behavior @legacy_default_plan_assignment_behavior end |
#message_builder ⇒ Object
Optional global message builder proc for human copy (i18n/hooks) Signature suggestion: (context:, **kwargs) -> string Contexts used: :over_limit, :grace, :feature_denied Example kwargs: limit_key:, current_usage:, limit_amount:, grace_ends_at:, feature_key:, plan_name:
42 43 44 |
# File 'lib/pricing_plans/configuration.rb', line 42 def @message_builder end |
#period_cycle ⇒ Object
Returns the value of attribute period_cycle.
16 17 18 |
# File 'lib/pricing_plans/configuration.rb', line 16 def period_cycle @period_cycle end |
#plan_owner_class ⇒ Object
Returns the value of attribute plan_owner_class.
43 44 45 |
# File 'lib/pricing_plans/configuration.rb', line 43 def plan_owner_class @plan_owner_class end |
#plans ⇒ Object (readonly)
Returns the value of attribute plans.
64 65 66 |
# File 'lib/pricing_plans/configuration.rb', line 64 def plans @plans end |
#price_cache ⇒ Object
Cache for Stripe prices. Defaults to in-memory store if nil. Should respond to read/write with ttl.
54 55 56 |
# File 'lib/pricing_plans/configuration.rb', line 54 def price_cache @price_cache end |
#price_cache_ttl ⇒ Object
Seconds for cache TTL for Stripe lookups
56 57 58 |
# File 'lib/pricing_plans/configuration.rb', line 56 def price_cache_ttl @price_cache_ttl end |
#price_components_resolver ⇒ Object
Semantic pricing components resolver hook: ->(plan, interval) { PriceComponents | nil }
50 51 52 |
# File 'lib/pricing_plans/configuration.rb', line 50 def price_components_resolver @price_components_resolver end |
#price_label_resolver ⇒ Object
Optional: custom resolver for displaying price labels from processor Signature: ->(plan) { "$amount/mo" }
46 47 48 |
# File 'lib/pricing_plans/configuration.rb', line 46 def price_label_resolver @price_label_resolver end |
#redirect_on_blocked_limit ⇒ Object
When a limit check blocks, controllers can redirect to a global default target. Accepts:
- Symbol: a controller helper to call (e.g., :pricing_path)
- String: an absolute/relative path or full URL
- Proc: instance-exec'd in the controller (self is the controller). Signature: ->(result) { ... } Result contains: limit_key, plan_owner, message, metadata
37 38 39 |
# File 'lib/pricing_plans/configuration.rb', line 37 def redirect_on_blocked_limit @redirect_on_blocked_limit end |
Class Method Details
.legacy_default_plan_assignment_behaviors_description ⇒ Object
11 12 13 14 |
# File 'lib/pricing_plans/configuration.rb', line 11 def self.legacy_default_plan_assignment_behaviors_description descriptions = LEGACY_DEFAULT_PLAN_ASSIGNMENT_BEHAVIORS.map(&:inspect) "#{descriptions[0..-2].join(', ')}, or #{descriptions.last}" end |
Instance Method Details
#controller_plan_owner(method_name = nil, &block) ⇒ Object
Global controller plan owner resolver API Usage:
config.controller_plan_owner :current_organization
# or
config.controller_plan_owner { current_account }
122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/pricing_plans/configuration.rb', line 122 def controller_plan_owner(method_name = nil, &block) if method_name @controller_plan_owner_method = method_name.to_sym @controller_plan_owner_proc = nil elsif block_given? @controller_plan_owner_proc = block @controller_plan_owner_method = nil else @controller_plan_owner_method end end |
#on_block(limit_key = nil) {|plan_owner, limit_key| ... } ⇒ Object
Register a callback for block events.
155 156 157 158 159 |
# File 'lib/pricing_plans/configuration.rb', line 155 def on_block(limit_key = nil, &block) raise PricingPlans::ConfigurationError, "Block required for on_block" unless block_given? key = limit_key || :_all @event_handlers[:block][key] = block end |
#on_grace_start(limit_key = nil) {|plan_owner, limit_key, grace_ends_at| ... } ⇒ Object
Register a callback for grace period start events.
146 147 148 149 150 |
# File 'lib/pricing_plans/configuration.rb', line 146 def on_grace_start(limit_key = nil, &block) raise PricingPlans::ConfigurationError, "Block required for on_grace_start" unless block_given? key = limit_key || :_all @event_handlers[:grace_start][key] = block end |
#on_warning(limit_key = nil) {|plan_owner, limit_key, threshold| ... } ⇒ Object
Register a callback for warning events.
137 138 139 140 141 |
# File 'lib/pricing_plans/configuration.rb', line 137 def on_warning(limit_key = nil, &block) raise PricingPlans::ConfigurationError, "Block required for on_warning" unless block_given? key = limit_key || :_all @event_handlers[:warning][key] = block end |
#plan(key, &block) ⇒ Object
107 108 109 110 111 112 113 114 |
# File 'lib/pricing_plans/configuration.rb', line 107 def plan(key, &block) raise PricingPlans::ConfigurationError, "Plan key must be a symbol" unless key.is_a?(Symbol) raise PricingPlans::ConfigurationError, "Plan #{key} already defined" if @plans.key?(key) plan_instance = PricingPlans::Plan.new(key) plan_instance.instance_eval(&block) @plans[key] = plan_instance end |
#select_defaults_from_dsl! ⇒ Object
169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/pricing_plans/configuration.rb', line 169 def select_defaults_from_dsl! # If not explicitly configured, derive from any plan marked via DSL sugar if @default_plan.nil? dsl_default = @plans.values.find(&:default?)&.key @default_plan = dsl_default if dsl_default end if @highlighted_plan.nil? dsl_highlighted = @plans.values.find(&:highlighted?)&.key @highlighted_plan = dsl_highlighted if dsl_highlighted end end |
#validate! ⇒ Object
161 162 163 164 165 166 167 168 |
# File 'lib/pricing_plans/configuration.rb', line 161 def validate! select_defaults_from_dsl! validate_required_settings! validate_plan_references! validate_dsl_markers! validate_legacy_default_plan_assignment_behavior! validate_plans! end |
#validate_dsl_markers! ⇒ Object
182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/pricing_plans/configuration.rb', line 182 def validate_dsl_markers! defaults = @plans.values.select(&:default?) highlights = @plans.values.select(&:highlighted?) if defaults.size > 1 keys = defaults.map(&:key).join(", ") raise PricingPlans::ConfigurationError, "Multiple plans marked default via DSL: #{keys}. Only one plan can be default." end if highlights.size > 1 keys = highlights.map(&:key).join(", ") raise PricingPlans::ConfigurationError, "Multiple plans marked highlighted via DSL: #{keys}. Only one plan can be highlighted." end end |