featury 1.0.0.rc13 → 1.0.0.rc15

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: 97cc910762d980a170b075f98d2b5fe4cff87af8680477a06805fd31f0f9576b
4
- data.tar.gz: 14ebb9a2d462b8414d5291a64b1a8d7c4b3957a3ad3669ebd88fc39c821c5ec4
3
+ metadata.gz: dbbace100047ab60a1b441ad2812b3fcbaeaa71c98d4e9a2e6d8a822c5591968
4
+ data.tar.gz: 3d4374fd97c7e11e64772694dadea54fd6cbc7e5e919521e09da2595cef40eb0
5
5
  SHA512:
6
- metadata.gz: 6ddf5182c50a1476a46d5ab336a0cb11baf3e0c9c72d27c71e51b5b5b1134376972aede1c3b0d334f3dc5b621096695ca45cc9e058b14a31816c3e11b946bf57
7
- data.tar.gz: 8584f3fec8b9bdf944923754fe27ffcb54ac3b13b9ed5e4393449ce6c2505b6760418f3c84651e55ce80a9c276e95a8c8df9d8f702b2fb039051973d48036148
6
+ metadata.gz: b59e1f386a652e903301b9cd1a180bf17ed0086aa676eac215b99bc296915cfb4850f17a076697461427b7a9f398e48016c6b81c70a7bf598629af7bd9f9484b
7
+ data.tar.gz: 31bfe86e8a32193ee3e7a727a7214193a6ecd7edea92208afdc29c7381543c8538af191c0d73aeeaf7c32bd8a5da052204341f48b7e842b21a06ee0502a790cb
data/README.md CHANGED
@@ -26,7 +26,7 @@ gem "featury"
26
26
  #### Basic class for your features
27
27
 
28
28
  For instance, assume that you are utilizing Flipper for managing features.
29
- In such scenario, the base class could potentially be structured as follows:
29
+ In such a scenario, the base class could potentially be structured as follows:
30
30
 
31
31
  ```ruby
32
32
  class ApplicationFeature < Featury::Base
@@ -45,19 +45,27 @@ class ApplicationFeature < Featury::Base
45
45
  action :disable do |features:, **options|
46
46
  features.all? { |feature| Flipper.disable(feature, *options.values) }
47
47
  end
48
+
49
+ before do |action:, features:|
50
+ Slack::API::Notify.call!(action:, features:)
51
+ end
52
+
53
+ after :enabled?, :disabled? do |action:, features:|
54
+ Slack::API::Notify.call!(action:, features:)
55
+ end
48
56
  end
49
57
  ```
50
58
 
51
59
  #### Features of your project
52
60
 
53
61
  ```ruby
54
- class UserFeature::Onboarding < ApplicationFeature
62
+ class User::OnboardingFeature < ApplicationFeature
63
+ prefix :user_onboarding
64
+
55
65
  resource :user, type: User
56
66
 
57
67
  condition ->(resources:) { resources.user.onboarding_awaiting? }
58
68
 
59
- prefix :user_onboarding
60
-
61
69
  features :passage # => :user_onboarding_passage
62
70
 
63
71
  groups BillingFeature,
@@ -104,16 +112,16 @@ Each of these actions will be applied to every feature flag.
104
112
  Subsequently, the outcome of these actions will be contingent upon the combined results of all feature flags.
105
113
 
106
114
  ```ruby
107
- UserFeature::Onboarding.enabled?(user:) # => true
108
- UserFeature::Onboarding.disabled?(user:) # => false
109
- UserFeature::Onboarding.enable(user:) # => true
110
- UserFeature::Onboarding.disable(user:) # => true
115
+ User::OnboardingFeature.enabled?(user:) # => true
116
+ User::OnboardingFeature.disabled?(user:) # => false
117
+ User::OnboardingFeature.enable(user:) # => true
118
+ User::OnboardingFeature.disable(user:) # => true
111
119
  ```
112
120
 
113
121
  You can also utilize the `with` method to pass necessary arguments.
114
122
 
115
123
  ```ruby
116
- feature = UserFeature::Onboarding.with(user:)
124
+ feature = User::OnboardingFeature.with(user:)
117
125
 
118
126
  feature.enabled? # => true
119
127
  feature.disabled? # => false
@@ -129,6 +137,18 @@ In the preceding example, there might be a scenario where the payment system is
129
137
  undergoing technical maintenance and therefore is temporarily shut down.
130
138
  Consequently, the onboarding process for new users will be halted until further notice.
131
139
 
140
+ #### Information about features
141
+
142
+ ```ruby
143
+ info = User::OnboardingFeature.info
144
+ ```
145
+
146
+ ```ruby
147
+ info.features # Feature flags within one class.
148
+ info.groups # Feature groups within one class.
149
+ info.tree # Tree of feature flags starting from the current class.
150
+ ```
151
+
132
152
  ## Contributing
133
153
 
134
154
  This project is intended to be a safe, welcoming space for collaboration.
@@ -65,7 +65,7 @@ module Featury
65
65
  [resource.name, inputs.public_send(resource.name)]
66
66
  end
67
67
 
68
- inputs.action.block.call(features: inputs.collection_of_features.list, **options)
68
+ inputs.action.block.call(features: inputs.collection_of_features.full_names, **options)
69
69
  end
70
70
 
71
71
  def groups_are_true
data/lib/featury/base.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Featury
4
4
  class Base
5
+ include Info::DSL
5
6
  include Context::DSL
6
7
  include Actions::DSL
7
8
  include Callbacks::DSL
@@ -3,10 +3,11 @@
3
3
  module Featury
4
4
  module Callbacks
5
5
  class Callback
6
- attr_reader :block
6
+ attr_reader :desired_actions, :block
7
7
 
8
- def initialize(stage, block:)
8
+ def initialize(stage:, desired_actions:, block:)
9
9
  @stage = stage.to_sym
10
+ @desired_actions = desired_actions
10
11
  @block = block
11
12
  end
12
13
 
@@ -10,12 +10,21 @@ module Featury
10
10
  @collection = collection
11
11
  end
12
12
 
13
+ def desired_actions(include:)
14
+ Collection.new(
15
+ filter do |callback|
16
+ callback.desired_actions.blank? ||
17
+ callback.desired_actions.include?(include)
18
+ end
19
+ )
20
+ end
21
+
13
22
  def before
14
- @before ||= Collection.new(filter(&:before?))
23
+ Collection.new(filter(&:before?))
15
24
  end
16
25
 
17
26
  def after
18
- @after ||= Collection.new(filter(&:after?))
27
+ Collection.new(filter(&:after?))
19
28
  end
20
29
  end
21
30
  end
@@ -17,17 +17,19 @@ module Featury
17
17
 
18
18
  private
19
19
 
20
- def before
20
+ def before(*actions)
21
21
  collection_of_callbacks << Callback.new(
22
- :before,
23
- block: ->(action:, features:) { yield(action:, features:) }
22
+ stage: :before,
23
+ desired_actions: actions,
24
+ block: ->(**arguments) { yield(**arguments) }
24
25
  )
25
26
  end
26
27
 
27
- def after
28
+ def after(*actions)
28
29
  collection_of_callbacks << Callback.new(
29
- :after,
30
- block: ->(action:, features:) { yield(action:, features:) }
30
+ stage: :after,
31
+ desired_actions: actions,
32
+ block: ->(**arguments) { yield(**arguments) }
31
33
  )
32
34
  end
33
35
 
@@ -8,13 +8,13 @@ module Featury
8
8
  end
9
9
 
10
10
  def initialize(action:, callbacks:, features:)
11
- @callbacks = callbacks
12
11
  @action = action
12
+ @callbacks = callbacks
13
13
  @features = features
14
14
  end
15
15
 
16
16
  def call!
17
- @callbacks.each do |callback|
17
+ @callbacks.desired_actions(include: @action).each do |callback|
18
18
  callback.block.call(action: @action, features: @features)
19
19
  end
20
20
  end
@@ -9,7 +9,7 @@ module Featury
9
9
  Featury::Callbacks::Service.call!(
10
10
  action: action.name,
11
11
  callbacks: collection_of_callbacks.before,
12
- features: collection_of_features.list
12
+ features: collection_of_features.full_names
13
13
  )
14
14
 
15
15
  result = super
@@ -17,7 +17,7 @@ module Featury
17
17
  Featury::Callbacks::Service.call!(
18
18
  action: action.name,
19
19
  callbacks: collection_of_callbacks.after,
20
- features: collection_of_features.list
20
+ features: collection_of_features.full_names
21
21
  )
22
22
 
23
23
  result
@@ -10,8 +10,8 @@ module Featury
10
10
  @collection = collection
11
11
  end
12
12
 
13
- def list
14
- @list ||= map { |feature| :"#{feature.prefix}_#{feature.name}" }
13
+ def full_names
14
+ map(&:full_name)
15
15
  end
16
16
  end
17
17
  end
@@ -3,12 +3,14 @@
3
3
  module Featury
4
4
  module Features
5
5
  class Feature
6
- attr_reader :prefix, :name
7
-
8
6
  def initialize(prefix, name)
9
7
  @prefix = prefix
10
8
  @name = name
11
9
  end
10
+
11
+ def full_name
12
+ :"#{@prefix}_#{@name}"
13
+ end
12
14
  end
13
15
  end
14
16
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Featury
4
+ module Info
5
+ module DSL
6
+ def self.included(base)
7
+ base.extend(ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ def info
12
+ Featury::Info::Result.new(
13
+ features: collection_of_features.full_names,
14
+ groups: collection_of_groups.map(&:group),
15
+ tree: collection_of_features.full_names.concat(
16
+ collection_of_groups.map do |group|
17
+ group.group.info.tree
18
+ end
19
+ )
20
+ )
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Featury
4
+ module Info
5
+ class Result
6
+ attr_reader :features, :groups, :tree
7
+
8
+ def initialize(features:, groups:, tree:)
9
+ @features = features
10
+ @groups = groups
11
+ @tree = tree
12
+ end
13
+ end
14
+ end
15
+ end
@@ -5,7 +5,7 @@ module Featury
5
5
  MAJOR = 1
6
6
  MINOR = 0
7
7
  PATCH = 0
8
- PRE = "rc13"
8
+ PRE = "rc15"
9
9
 
10
10
  STRING = [MAJOR, MINOR, PATCH, PRE].compact.join(".")
11
11
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: featury
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.rc13
4
+ version: 1.0.0.rc15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anton Sokolov
@@ -179,6 +179,8 @@ files:
179
179
  - lib/featury/groups/collection.rb
180
180
  - lib/featury/groups/dsl.rb
181
181
  - lib/featury/groups/group.rb
182
+ - lib/featury/info/dsl.rb
183
+ - lib/featury/info/result.rb
182
184
  - lib/featury/resources/collection.rb
183
185
  - lib/featury/resources/dsl.rb
184
186
  - lib/featury/resources/resource.rb