plan_features 0.1.0 → 0.3.0

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: 0f6d3f70ba4ccec42364f9cd047fc528fd65359f672a8d4ab432814db65d6130
4
- data.tar.gz: 9de014c4f152137a0263ad2287916f2d53579c5b1d0d1fb23bb177b5b3277186
3
+ metadata.gz: 500cb4693e7ccbe5af5b6ac882c5e0ef6e26a954be886c50727fe321df182e8b
4
+ data.tar.gz: f79ec09d1598fc35f9ad7bc2cf24a69ae6f743c6f2b64f64f14e8676e43473d6
5
5
  SHA512:
6
- metadata.gz: 5d8b556b708ff38f4604742a2ba679e4569a373211d9b772fc43d991b3f009eb68bf8becbde16dfc2b8b677224298345b12ffaa0644306110e620c77300d632a
7
- data.tar.gz: d40d30f4b668650bf7bb5effa19096292fb7adf1c8d64e4f1be5a3780b4467310c2fc8b920b4d5abe2a9e35503cad3ede1a2cbdc0b7a401e0cc1383d9f01d8b2
6
+ metadata.gz: 50a50907f7408157ebf2a1a6fbc0e75223294b8b3795ad6eb61c28236da9cd2dda6f1766e852ea9c894c2f37433fc12d72f33d077e9a1b506466ea81c0462bfd
7
+ data.tar.gz: 4bd1b29a1a5701738e08f547736fa3d8dc22f57652c978aaa5ce796910f83f7abf0ca0e627e34287cc4fecb394f47f8a959d1cddcb74877edd88931bec2ece5b
data/README.md CHANGED
@@ -1,10 +1,118 @@
1
1
  # PlanFeatures
2
- Short description and motivation.
2
+
3
+ This is a gem for Rails to help you with which features are available for which plans in your paid app.
4
+
5
+ The idea is that you have a set of plans and each plan has a set of features. We want an easy way to list all available
6
+ plans and their features and we want the ability to inherit features from previous plans. Let's say you have a Free plan
7
+ with Feature A and Feature B. When you upgrade to the Paid plan which gives you Feature C and Feature D we still want the
8
+ checks for Feature A and Feature B to return true.
3
9
 
4
10
  ## Usage
5
- How to use my plugin.
11
+
12
+ Create a new file `config/plans.yml` or whatever and create a new initializer `config/initializers/plan_features.rb` with:
13
+
14
+ ```
15
+ PlanFeatures.configure do |config|
16
+ config.plans_file_path = Rails.root.join("config", "plans.yml")
17
+ end
18
+ ```
19
+
20
+ ## Plan configuration
21
+
22
+ Your `plans.yml` could look something like this:
23
+
24
+ ```
25
+ free:
26
+ name: "Free"
27
+ features:
28
+ feature_a:
29
+ description: "Feature A"
30
+ feature_b:
31
+ description: "Feature B"
32
+
33
+ paid:
34
+ name: "Paid"
35
+ features:
36
+ feature_c:
37
+ description: "Feature C"
38
+ feature_d:
39
+ description: "Feature D"
40
+ prices:
41
+ monthly:
42
+ product: STRIPE_ID
43
+ amount: 500
44
+ ```
45
+
46
+ This sets up two plans where the `free` plan has the features A and B and the paid plan has the features C and D.
47
+
48
+ ## Feature inheritance from previous plans
49
+
50
+ We wouldn't want the paid user to lose access to the features from the Free plan. So let's go ahead and set the previous plan
51
+ on the `paid` plan definition to `free`:
52
+
53
+ ```
54
+ paid:
55
+ name: "Paid"
56
+ previous: free
57
+ features:
58
+ # features from the above example
59
+ ```
60
+
61
+ Now it'll inherit the features defined in the Free plan.
62
+
63
+ We can check if a feature is available in our code:
64
+
65
+ ```
66
+ plan = PricingFeatures::Pricing.find_by_identifier(:paid)
67
+ plan.has_feature?(:feature_c)
68
+ # => true
69
+ ```
70
+
71
+ ## Features with limits
72
+
73
+ Sometimes features aren't just boolean features. You might be able to create "posts", but on the free plan you can only create 2, but on the paid plan you can create let's say 50. We can define that like so:
74
+
75
+ ```
76
+ free:
77
+ name: "Free"
78
+ features:
79
+ posts:
80
+ description: "2 posts"
81
+ limit: 2
82
+
83
+ paid:
84
+ name: "Paid"
85
+ features:
86
+ posts:
87
+ description: "50 posts"
88
+ limit: 50
89
+ ```
90
+
91
+ In your code you can check for the limit of a feature with:
92
+
93
+ ```
94
+ free_plan = PlanFeatures::Pricing.find_by_identifier(:free)
95
+ free_plan.limit_for(:posts)
96
+ # => 2
97
+
98
+ paid_plan = PlanFeatures::Pricing.find_by_identifier(:paid)
99
+ paid_plan.limit_for(:posts)
100
+ # => 50
101
+ ```
102
+
103
+ ### Metadata
104
+
105
+ You can add metadata to a plan by using the `metadata` key. Example:
106
+
107
+ ```
108
+ paid:
109
+ name: "Paid"
110
+ metadata:
111
+ popular: true
112
+ ```
6
113
 
7
114
  ## Installation
115
+
8
116
  Add this line to your application's Gemfile:
9
117
 
10
118
  ```ruby
@@ -12,17 +120,21 @@ gem "plan_features"
12
120
  ```
13
121
 
14
122
  And then execute:
123
+
15
124
  ```bash
16
125
  $ bundle
17
126
  ```
18
127
 
19
128
  Or install it yourself as:
129
+
20
130
  ```bash
21
131
  $ gem install plan_features
22
132
  ```
23
133
 
24
134
  ## Contributing
135
+
25
136
  Contribution directions go here.
26
137
 
27
138
  ## License
139
+
28
140
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -2,7 +2,7 @@ module PricingFeatures
2
2
  class Feature
3
3
  include ActiveModel::Model
4
4
 
5
- attr_accessor :description, :amount, :hidden
5
+ attr_accessor :identifier, :description, :limit, :hidden
6
6
 
7
7
  alias_method :hidden?, :hidden
8
8
  end
@@ -2,16 +2,14 @@ require_relative "feature"
2
2
 
3
3
  module PlanFeatures
4
4
  class Pricing
5
- attr_accessor :name, :plan_identifier, :interval, :stripe_id, :features, :prices, :previous, :popular
5
+ attr_accessor :name, :plan_identifier, :interval, :stripe_id, :features, :prices, :previous, :metadata
6
6
 
7
7
  include ActiveModel::Model
8
8
 
9
9
  def self.boosts
10
- @boosts ||= begin
11
- if File.exist?(Rails.root.join("config", "account_boosts.yml"))
10
+ @boosts ||= if File.exist?(Rails.root.join("config", "account_boosts.yml"))
12
11
  YAML.load_file(Rails.root.join("config", "account_boosts.yml"))
13
12
  end
14
- end
15
13
  end
16
14
 
17
15
  def self.find_by_identifier(id)
@@ -31,11 +29,11 @@ module PlanFeatures
31
29
  @all_plans ||= YAML.load_file(::PlanFeatures.configuration.plans_file_path).map do |plan, attributes|
32
30
  Pricing.new(
33
31
  plan_identifier: plan,
34
- popular: attributes["popular"],
35
32
  name: attributes["name"],
36
33
  features: attributes["features"],
37
34
  prices: attributes["prices"],
38
- previous: attributes["previous"]
35
+ previous: attributes["previous"],
36
+ metadata: attributes["metadata"]&.with_indifferent_access,
39
37
  )
40
38
  end
41
39
  end
@@ -64,8 +62,8 @@ module PlanFeatures
64
62
  end
65
63
  end
66
64
 
67
- def amount_for(feature)
68
- features.dig(feature.to_s, "amount")
65
+ def limit_for(feature)
66
+ features.dig(feature.to_s, "limit")
69
67
  end
70
68
 
71
69
  def free?
@@ -76,27 +74,11 @@ module PlanFeatures
76
74
  prices&.any?
77
75
  end
78
76
 
79
- def pricing_id(interval = "monthly")
80
- if interval == "monthly"
81
- monthly_pricing_id
82
- else
83
- yearly_pricing_id
84
- end
85
- end
86
-
87
77
  def pricing_id(name: :monthly)
88
78
  return nil if prices.nil?
89
79
  prices[name.to_s]["product"]
90
80
  end
91
81
 
92
- def monthly_pricing_id
93
- pricing_id(name: :monthly)
94
- end
95
-
96
- def yearly_pricing_id
97
- pricing_id(name: :yearly)
98
- end
99
-
100
82
  def price(name: :monthly)
101
83
  return nil if prices.nil?
102
84
  prices[name.to_s]["amount"] / 100
@@ -110,11 +92,12 @@ module PlanFeatures
110
92
  def display_features
111
93
  features.map do |identifier, attributes|
112
94
  PricingFeatures::Feature.new(
95
+ identifier: identifier,
113
96
  description: attributes["description"],
114
- amount: attributes["amount"],
115
- hidden: attributes["hidden"],
97
+ limit: attributes["limit"],
98
+ hidden: attributes["hidden"]
116
99
  )
117
- end.compact.filter{|f| !f.hidden? }
100
+ end.compact.filter { |f| !f.hidden? }
118
101
  end
119
102
  end
120
103
  end
@@ -1,3 +1,3 @@
1
1
  module PlanFeatures
2
- VERSION = "0.1.0"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plan_features
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jesper Christiansen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-10 00:00:00.000000000 Z
11
+ date: 2023-11-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails