flagship 0.4.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +6 -4
- data/CHANGELOG.md +29 -0
- data/README.md +93 -0
- data/flagship.gemspec +1 -1
- data/lib/flagship/context.rb +26 -7
- data/lib/flagship/dsl.rb +17 -1
- data/lib/flagship/flagset.rb +3 -2
- data/lib/flagship/version.rb +1 -1
- data/lib/flagship.rb +57 -32
- metadata +8 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 60210addd43057e1808189582ab298a84f14bb70468c1685e676ceb5481a7a8a
|
4
|
+
data.tar.gz: 4f85d9c988e71f2d219938310990757869269cf31e84706e093640f0e07b1326
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 43dd867d1d2a6de1433833709fdd9c251ee095fd088a0d4f024fc802d966067f24c80a4d0615202892663014c03f22ba295dacc4c55610982ed2d5f4316a3c9f
|
7
|
+
data.tar.gz: 45152c852249cfa8692da6c234f1d6f246ab30c1111c7458436ea8a99ab792077a0af4608570954bf9a4ea4ab2aff859a09e5067453d0867552acf68b7fc15e2
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,34 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## [0.7.0] - 2020-05-01
|
4
|
+
|
5
|
+
### Fixed
|
6
|
+
|
7
|
+
- Make context thread safe [#32](https://github.com/yuya-takeyama/flagship/pull/32) ([@mtsmfm](https://github.com/mtsmfm))
|
8
|
+
|
9
|
+
## [0.6.1] - 2017-05-17
|
10
|
+
|
11
|
+
### Added
|
12
|
+
|
13
|
+
- Add separated methods to clear state [#30](https://github.com/yuya-takeyama/flagship/pull/30)
|
14
|
+
|
15
|
+
## [0.6.0] - 2017-05-15
|
16
|
+
|
17
|
+
### Added
|
18
|
+
|
19
|
+
- Add `Flagship.with_context` method to apply temporal changes to context variables [#26](https://github.com/yuya-takeyama/flagship/pull/26)
|
20
|
+
- Now `Flagship.clear_state` clears context variables as well [#27](https://github.com/yuya-takeyama/flagship/pull/27)
|
21
|
+
|
22
|
+
### Changed
|
23
|
+
|
24
|
+
- Allow `Flagship.set_context` to set multiple variables at once using `Hash` [#25](https://github.com/yuya-takeyama/flagship/pull/25)
|
25
|
+
|
26
|
+
## [0.5.0] - 2017-01-07
|
27
|
+
|
28
|
+
- Documented about helper methods [#21](https://github.com/yuya-takeyama/flagship/pull/21)
|
29
|
+
- Helper methods can be specified as a `Symbol` [#21](https://github.com/yuya-takeyama/flagship/pull/21)
|
30
|
+
- Helper methods are extended [#22](https://github.com/yuya-takeyama/flagship/pull/22)
|
31
|
+
|
3
32
|
## [0.4.0] - 2016-12-23
|
4
33
|
|
5
34
|
### Added
|
data/README.md
CHANGED
@@ -62,6 +62,24 @@ Or you can set a method too.
|
|
62
62
|
Flagship.set_context :current_user, method(:current_user)
|
63
63
|
```
|
64
64
|
|
65
|
+
### Apply temporal changes to context variables
|
66
|
+
|
67
|
+
Using `Flagship.with_context` method, you can override context variables temporarily.
|
68
|
+
|
69
|
+
```rb
|
70
|
+
class User
|
71
|
+
def enabled_features
|
72
|
+
Flagship.with_context current_user: self do
|
73
|
+
Flagship.features.enabled.map(&:key)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
```
|
78
|
+
|
79
|
+
It's useful when you implement a method using `Flagship` into some domain objects.
|
80
|
+
|
81
|
+
By using this, values specified in the argument is overridden and other values are inherited.
|
82
|
+
|
65
83
|
### Extend flagset
|
66
84
|
|
67
85
|
```rb
|
@@ -147,6 +165,81 @@ Flagship.define :blog do
|
|
147
165
|
end
|
148
166
|
```
|
149
167
|
|
168
|
+
## Helper methods
|
169
|
+
|
170
|
+
You can define helpers as normal methods with `def`. Methods can be used within blocks, procs, or as symbolic names for if statements to tidy up your code.
|
171
|
+
|
172
|
+
```rb
|
173
|
+
Flagship.define :blog do
|
174
|
+
def is_author(comment, user)
|
175
|
+
comment.author == user
|
176
|
+
end
|
177
|
+
|
178
|
+
def can_view_comment(context)
|
179
|
+
context.current_user.moderator?
|
180
|
+
end
|
181
|
+
|
182
|
+
enable :comment, if: :can_view_comment
|
183
|
+
enable :comment_deletion, if: ->(context) { is_author(context.comment, context.current_user) }
|
184
|
+
end
|
185
|
+
```
|
186
|
+
|
187
|
+
To share helpers, you can simply include them as modules.
|
188
|
+
|
189
|
+
```rb
|
190
|
+
module FlagHelpers
|
191
|
+
def is_author(context)
|
192
|
+
context.comment.author == context.current_user
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
Flagship.define :development do
|
197
|
+
include FlagHelpers
|
198
|
+
enable :delete, if: :is_author
|
199
|
+
end
|
200
|
+
|
201
|
+
Flagship.define :production do
|
202
|
+
include FlagHelpers
|
203
|
+
enable :delete, if: :is_author
|
204
|
+
end
|
205
|
+
```
|
206
|
+
|
207
|
+
And you can also extend helper methods from base flagset.
|
208
|
+
|
209
|
+
```rb
|
210
|
+
Flagship.define :base do
|
211
|
+
def is_author(context)
|
212
|
+
context.comment.author == context.current_user
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
Flagship.define :production do
|
217
|
+
enable :delete, if: :is_author
|
218
|
+
end
|
219
|
+
```
|
220
|
+
|
221
|
+
### Testing
|
222
|
+
|
223
|
+
#### RSpec
|
224
|
+
|
225
|
+
It's recommended to clear state of `Flagship` before the suite and after the each tests.
|
226
|
+
|
227
|
+
You can do it by configuring like below:
|
228
|
+
|
229
|
+
```rb
|
230
|
+
RSpec.configure do |config|
|
231
|
+
config.before(:suite) do
|
232
|
+
Flagship.clear_context
|
233
|
+
Flagship.clear_current_flagset
|
234
|
+
end
|
235
|
+
|
236
|
+
config.after(:each) do
|
237
|
+
Flagship.clear_context
|
238
|
+
Flagship.clear_current_flagset
|
239
|
+
end
|
240
|
+
end
|
241
|
+
```
|
242
|
+
|
150
243
|
## Development
|
151
244
|
|
152
245
|
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/flagship.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
22
|
spec.require_paths = ["lib"]
|
23
23
|
|
24
|
-
spec.add_development_dependency "bundler", "
|
24
|
+
spec.add_development_dependency "bundler", "> 1.13"
|
25
25
|
spec.add_development_dependency "rake", "~> 10.0"
|
26
26
|
spec.add_development_dependency "rspec", "~> 3.5.0"
|
27
27
|
end
|
data/lib/flagship/context.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
1
3
|
class Flagship::Context
|
2
|
-
|
3
|
-
|
4
|
-
end
|
4
|
+
extend Forwardable
|
5
|
+
def_delegators :current_values, :clear
|
5
6
|
|
6
7
|
def __set(key, value)
|
7
|
-
|
8
|
+
current_values[key.to_sym] = value
|
8
9
|
end
|
9
10
|
|
10
11
|
def method_missing(name, args = [], &block)
|
11
|
-
if
|
12
|
-
value =
|
12
|
+
if current_values.key?(name)
|
13
|
+
value = current_values[name]
|
13
14
|
|
14
15
|
if value.respond_to?(:call)
|
15
16
|
value.call
|
@@ -22,6 +23,24 @@ class Flagship::Context
|
|
22
23
|
end
|
23
24
|
|
24
25
|
def respond_to_missing?(name, include_private = false)
|
25
|
-
|
26
|
+
current_values.key?(name) or super
|
27
|
+
end
|
28
|
+
|
29
|
+
def with_values(new_values, &block)
|
30
|
+
original_values = current_values
|
31
|
+
self.current_values = current_values.dup.merge(new_values)
|
32
|
+
block.call
|
33
|
+
ensure
|
34
|
+
self.current_values = original_values
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def current_values
|
40
|
+
Thread.current[:__flagship_context_values] ||= {}
|
41
|
+
end
|
42
|
+
|
43
|
+
def current_values=(new_values)
|
44
|
+
Thread.current[:__flagship_context_values] = new_values
|
26
45
|
end
|
27
46
|
end
|
data/lib/flagship/dsl.rb
CHANGED
@@ -11,14 +11,26 @@ class Flagship::Dsl
|
|
11
11
|
@definition = block
|
12
12
|
@base_tags = {}
|
13
13
|
|
14
|
+
if @base
|
15
|
+
@base.helper_methods.each do |method|
|
16
|
+
define_singleton_method(method.name, &method)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
14
20
|
instance_eval(&@definition)
|
15
21
|
|
16
|
-
|
22
|
+
helper_methods = singleton_methods.map { |sym| method(sym) }
|
23
|
+
@flagset = ::Flagship::Flagset.new(@key, @features, @base, helper_methods)
|
17
24
|
end
|
18
25
|
|
19
26
|
def enable(key, opts = {})
|
20
27
|
tags = opts.dup
|
21
28
|
condition = tags.delete(:if)
|
29
|
+
# convert to proc
|
30
|
+
if condition.is_a?(Symbol)
|
31
|
+
sym = condition
|
32
|
+
condition = ->(context) { method(sym).call(context) }
|
33
|
+
end
|
22
34
|
|
23
35
|
if condition
|
24
36
|
@features[key] = ::Flagship::Feature.new(key, condition, @context, @base_tags.merge(tags))
|
@@ -49,4 +61,8 @@ class Flagship::Dsl
|
|
49
61
|
def disabled?(key)
|
50
62
|
@flagset.disabled?(key)
|
51
63
|
end
|
64
|
+
|
65
|
+
def include(mod)
|
66
|
+
extend mod
|
67
|
+
end
|
52
68
|
end
|
data/lib/flagship/flagset.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
class Flagship::Flagset
|
2
|
-
attr_reader :key
|
2
|
+
attr_reader :key, :helper_methods
|
3
3
|
|
4
4
|
class UndefinedFlagError < ::StandardError; end
|
5
5
|
|
6
|
-
def initialize(key, features_hash, base = nil)
|
6
|
+
def initialize(key, features_hash, base = nil, helper_methods = [])
|
7
7
|
@key = key
|
8
8
|
@features = base ?
|
9
9
|
extend_features(features_hash, base) :
|
10
10
|
features_hash
|
11
|
+
@helper_methods = helper_methods
|
11
12
|
end
|
12
13
|
|
13
14
|
def enabled?(key)
|
data/lib/flagship/version.rb
CHANGED
data/lib/flagship.rb
CHANGED
@@ -9,46 +9,71 @@ require "flagship/flagsets_container"
|
|
9
9
|
module Flagship
|
10
10
|
class NoFlagsetSelectedError < ::StandardError; end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
class << self
|
13
|
+
def define(key, options = {}, &block)
|
14
|
+
context = self.default_context
|
15
|
+
base = options[:extend] ? self.get_flagset(options[:extend]) : nil
|
16
|
+
default_flagsets_container.add ::Flagship::Dsl.new(key, context, base, &block).flagset
|
17
|
+
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
19
|
+
def enabled?(key)
|
20
|
+
current_flagset.enabled?(key)
|
21
|
+
end
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
23
|
+
def set_context(key_or_hash, value=nil)
|
24
|
+
if key_or_hash.is_a?(Hash)
|
25
|
+
key_or_hash.each { |k, v| default_context.__set(k, v) }
|
26
|
+
else
|
27
|
+
default_context.__set(key_or_hash, value)
|
28
|
+
end
|
29
|
+
end
|
25
30
|
|
26
|
-
|
27
|
-
|
28
|
-
|
31
|
+
def with_context(values, &block)
|
32
|
+
default_context.with_values values do
|
33
|
+
block.call
|
34
|
+
end
|
35
|
+
end
|
29
36
|
|
30
|
-
|
31
|
-
|
32
|
-
|
37
|
+
def select_flagset(key)
|
38
|
+
@current_flagset = default_flagsets_container.get(key)
|
39
|
+
end
|
33
40
|
|
34
|
-
|
35
|
-
|
36
|
-
|
41
|
+
def features
|
42
|
+
current_flagset.features
|
43
|
+
end
|
37
44
|
|
38
|
-
|
39
|
-
|
40
|
-
|
45
|
+
def get_flagset(key)
|
46
|
+
default_flagsets_container.get(key)
|
47
|
+
end
|
41
48
|
|
42
|
-
|
43
|
-
|
44
|
-
|
49
|
+
def default_flagsets_container
|
50
|
+
@default_flagsts_container ||= ::Flagship::FlagsetsContainer.new
|
51
|
+
end
|
45
52
|
|
46
|
-
|
47
|
-
|
48
|
-
|
53
|
+
def current_flagset
|
54
|
+
@current_flagset or raise NoFlagsetSelectedError.new('No flagset is selected')
|
55
|
+
end
|
56
|
+
|
57
|
+
def default_context
|
58
|
+
@default_context ||= ::Flagship::Context.new
|
59
|
+
end
|
60
|
+
|
61
|
+
def clear_state
|
62
|
+
clear_flagsets_container
|
63
|
+
clear_current_flagset
|
64
|
+
clear_context
|
65
|
+
end
|
66
|
+
|
67
|
+
def clear_flagsets_container
|
68
|
+
@default_flagsts_container = nil
|
69
|
+
end
|
70
|
+
|
71
|
+
def clear_current_flagset
|
72
|
+
@current_flagset = nil
|
73
|
+
end
|
49
74
|
|
50
|
-
|
51
|
-
|
52
|
-
|
75
|
+
def clear_context
|
76
|
+
@default_context && @default_context.clear
|
77
|
+
end
|
53
78
|
end
|
54
79
|
end
|
metadata
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flagship
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yuya Takeyama
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-08-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.13'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.13'
|
27
27
|
- !ruby/object:Gem::Dependency
|
@@ -82,7 +82,7 @@ homepage: https://github.com/yuya-takeyama/flagship
|
|
82
82
|
licenses:
|
83
83
|
- MIT
|
84
84
|
metadata: {}
|
85
|
-
post_install_message:
|
85
|
+
post_install_message:
|
86
86
|
rdoc_options: []
|
87
87
|
require_paths:
|
88
88
|
- lib
|
@@ -97,9 +97,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
97
97
|
- !ruby/object:Gem::Version
|
98
98
|
version: '0'
|
99
99
|
requirements: []
|
100
|
-
|
101
|
-
|
102
|
-
signing_key:
|
100
|
+
rubygems_version: 3.1.2
|
101
|
+
signing_key:
|
103
102
|
specification_version: 4
|
104
103
|
summary: Ship/unship features using flags defined with declarative DSL
|
105
104
|
test_files: []
|