flipper-redis 0.20.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 38ed937a4141ea4dd894c5b12894a117d5117309106993ae73f541bbabf4ca52
4
- data.tar.gz: 79c9e9e33ff30120149967724ab170417cba12431cbae1dc46d243e4f2a4043c
3
+ metadata.gz: d75794c8cf100a5df75ec07ec97123cda83eb195ee7eab7d91b58b1aab04354e
4
+ data.tar.gz: 78ae668ed8767209136cfe09d05e8c6a67fc3e7bc9466f4a5637403a99c43706
5
5
  SHA512:
6
- metadata.gz: 12e3459fc127df7292e9288dd4a63cf7a8c6332dcefc2f0bdfd80e145b1966dd1cdbb95913616f998a602b26e7e8b1c71f59052fdccccdca68ab66ce00a683c5
7
- data.tar.gz: c7215cefbff7c825dca2a15d2e10b49c021aad72ff4b4d51ac8131b32173b42aad70f4f2a10da724431121bf19ce71dd10b6e912e6525c0c09a27aca7dc99901
6
+ metadata.gz: 513f65a411e1be74144e3870e3149724a78c5ce25692122f85657f50b149b95715473e01b5f423d74edec58d141fe45235246dbf206354b7747d9ad3bfecfd62
7
+ data.tar.gz: f1a5a543226d2d0fd55c2c817207541ded0bb09f49e152ca5bb40fbf0069c6e2d9a9d0c9cee0a1b4903177cdbc50f9fb2841e8b778dcc8e98d877792760d447a
@@ -1,30 +1,19 @@
1
- require 'pathname'
1
+ require 'bundler/setup'
2
2
  require 'logger'
3
3
 
4
- root_path = Pathname(__FILE__).dirname.join('..').expand_path
5
- lib_path = root_path.join('lib')
6
- $:.unshift(lib_path)
7
-
8
4
  require 'flipper/adapters/redis'
9
- options = {}
10
- if ENV['REDIS_URL']
11
- options[:url] = ENV['REDIS_URL']
12
- end
13
- client = Redis.new(options)
14
- adapter = Flipper::Adapters::Redis.new(client)
15
- flipper = Flipper.new(adapter)
16
5
 
17
- flipper[:stats].enable
6
+ Flipper[:stats].enable
18
7
 
19
- if flipper[:stats].enabled?
8
+ if Flipper[:stats].enabled?
20
9
  puts "Enabled!"
21
10
  else
22
11
  puts "Disabled!"
23
12
  end
24
13
 
25
- flipper[:stats].disable
14
+ Flipper[:stats].disable
26
15
 
27
- if flipper[:stats].enabled?
16
+ if Flipper[:stats].enabled?
28
17
  puts "Enabled!"
29
18
  else
30
19
  puts "Disabled!"
@@ -1,38 +1,27 @@
1
+ require 'bundler/setup'
1
2
  require 'pp'
2
- require 'pathname'
3
3
  require 'logger'
4
-
5
- root_path = Pathname(__FILE__).dirname.join('..').expand_path
6
- lib_path = root_path.join('lib')
7
- $:.unshift(lib_path)
8
-
9
4
  require 'flipper/adapters/redis'
10
5
 
11
- options = {}
12
- if ENV['REDIS_URL']
13
- options[:url] = ENV['REDIS_URL']
14
- end
15
- client = Redis.new(options)
16
- adapter = Flipper::Adapters::Redis.new(client)
17
- flipper = Flipper.new(adapter)
6
+ client = Redis.new
18
7
 
19
8
  # Register a few groups.
20
- Flipper.register(:admins) { |thing| thing.admin? }
21
- Flipper.register(:early_access) { |thing| thing.early_access? }
9
+ Flipper.register(:admins) { |actor| actor.admin? }
10
+ Flipper.register(:early_access) { |actor| actor.early_access? }
22
11
 
23
12
  # Create a user class that has flipper_id instance method.
24
13
  User = Struct.new(:flipper_id)
25
14
 
26
- flipper[:stats].enable
27
- flipper[:stats].enable_group :admins
28
- flipper[:stats].enable_group :early_access
29
- flipper[:stats].enable_actor User.new('25')
30
- flipper[:stats].enable_actor User.new('90')
31
- flipper[:stats].enable_actor User.new('180')
32
- flipper[:stats].enable_percentage_of_time 15
33
- flipper[:stats].enable_percentage_of_actors 45
15
+ Flipper[:stats].enable
16
+ Flipper[:stats].enable_group :admins
17
+ Flipper[:stats].enable_group :early_access
18
+ Flipper[:stats].enable_actor User.new('25')
19
+ Flipper[:stats].enable_actor User.new('90')
20
+ Flipper[:stats].enable_actor User.new('180')
21
+ Flipper[:stats].enable_percentage_of_time 15
22
+ Flipper[:stats].enable_percentage_of_actors 45
34
23
 
35
- flipper[:search].enable
24
+ Flipper[:search].enable
36
25
 
37
26
  print 'all keys: '
38
27
  pp client.keys
@@ -64,7 +53,7 @@ pp client.hgetall('search')
64
53
  puts
65
54
 
66
55
  puts 'flipper get of feature'
67
- pp adapter.get(flipper[:stats])
56
+ pp Flipper.adapter.get(Flipper[:stats])
68
57
  # flipper get of feature
69
58
  # {:boolean=>"true",
70
59
  # :groups=>#<Set: {"admins", "early_access"}>,
@@ -1,18 +1,7 @@
1
- require 'pp'
2
- require 'pathname'
3
- require 'logger'
4
- begin
5
- require 'redis-namespace'
6
- rescue LoadError
7
- puts 'you must have redis-namespace gem installed'
8
- exit 1
9
- end
10
-
11
- root_path = Pathname(__FILE__).dirname.join('..').expand_path
12
- lib_path = root_path.join('lib')
13
- $:.unshift(lib_path)
14
-
1
+ require 'bundler/setup'
2
+ require 'redis-namespace'
15
3
  require 'flipper/adapters/redis'
4
+
16
5
  options = {url: 'redis://127.0.0.1:6379'}
17
6
  if ENV['REDIS_URL']
18
7
  options[:url] = ENV['REDIS_URL']
@@ -23,8 +12,8 @@ adapter = Flipper::Adapters::Redis.new(namespaced_client)
23
12
  flipper = Flipper.new(adapter)
24
13
 
25
14
  # Register a few groups.
26
- Flipper.register(:admins) { |thing| thing.admin? }
27
- Flipper.register(:early_access) { |thing| thing.early_access? }
15
+ Flipper.register(:admins) { |actor| actor.admin? }
16
+ Flipper.register(:early_access) { |actor| actor.early_access? }
28
17
 
29
18
  # Create a user class that has flipper_id instance method.
30
19
  User = Struct.new(:flipper_id)
@@ -8,10 +8,10 @@ end
8
8
 
9
9
  Gem::Specification.new do |gem|
10
10
  gem.authors = ['John Nunemaker']
11
- gem.email = ['nunemaker@gmail.com']
11
+ gem.email = 'support@flippercloud.io'
12
12
  gem.summary = 'Redis adapter for Flipper'
13
13
  gem.license = 'MIT'
14
- gem.homepage = 'https://github.com/jnunemaker/flipper'
14
+ gem.homepage = 'https://www.flippercloud.io/docs/adapters/redis'
15
15
 
16
16
  gem.files = `git ls-files`.split("\n").select(&flipper_redis_files) + ['lib/flipper/version.rb']
17
17
  gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n").select(&flipper_redis_files)
@@ -21,5 +21,5 @@ Gem::Specification.new do |gem|
21
21
  gem.metadata = Flipper::METADATA
22
22
 
23
23
  gem.add_dependency 'flipper', "~> #{Flipper::VERSION}"
24
- gem.add_dependency 'redis', '>= 2.2', '< 5'
24
+ gem.add_dependency 'redis', '>= 3.0', '< 6'
25
25
  end
@@ -7,18 +7,28 @@ module Flipper
7
7
  class Redis
8
8
  include ::Flipper::Adapter
9
9
 
10
- # Private: The key that stores the set of known features.
11
- FeaturesKey = :flipper_features
12
-
13
10
  # Public: The name of the adapter.
14
11
  attr_reader :name
15
12
 
13
+ attr_reader :key_prefix
14
+
15
+ def features_key
16
+ "#{key_prefix}flipper_features"
17
+ end
18
+
19
+ def key_for(feature_name)
20
+ "#{key_prefix}#{feature_name}"
21
+ end
22
+
16
23
  # Public: Initializes a Redis flipper adapter.
17
24
  #
18
- # client - The Redis client to use. Feel free to namespace it.
19
- def initialize(client)
25
+ # client - The Redis client to use.
26
+ # key_prefix - an optional prefix with which to namespace
27
+ # flipper's Redis keys
28
+ def initialize(client, key_prefix: nil)
20
29
  @client = client
21
30
  @name = :redis
31
+ @key_prefix = key_prefix
22
32
  end
23
33
 
24
34
  # Public: The set of known features.
@@ -28,20 +38,28 @@ module Flipper
28
38
 
29
39
  # Public: Adds a feature to the set of known features.
30
40
  def add(feature)
31
- @client.sadd FeaturesKey, feature.key
41
+ if redis_sadd_returns_boolean?
42
+ @client.sadd? features_key, feature.key
43
+ else
44
+ @client.sadd features_key, feature.key
45
+ end
32
46
  true
33
47
  end
34
48
 
35
49
  # Public: Removes a feature from the set of known features.
36
50
  def remove(feature)
37
- @client.srem FeaturesKey, feature.key
38
- @client.del feature.key
51
+ if redis_sadd_returns_boolean?
52
+ @client.srem? features_key, feature.key
53
+ else
54
+ @client.srem features_key, feature.key
55
+ end
56
+ @client.del key_for(feature.key)
39
57
  true
40
58
  end
41
59
 
42
60
  # Public: Clears the gate values for a feature.
43
61
  def clear(feature)
44
- @client.del feature.key
62
+ @client.del key_for(feature.key)
45
63
  true
46
64
  end
47
65
 
@@ -70,14 +88,15 @@ module Flipper
70
88
  #
71
89
  # Returns true.
72
90
  def enable(feature, gate, thing)
91
+ feature_key = key_for(feature.key)
73
92
  case gate.data_type
74
93
  when :boolean
75
94
  clear(feature)
76
- @client.hset feature.key, gate.key, thing.value.to_s
95
+ @client.hset feature_key, gate.key, thing.value.to_s
77
96
  when :integer
78
- @client.hset feature.key, gate.key, thing.value.to_s
97
+ @client.hset feature_key, gate.key, thing.value.to_s
79
98
  when :set
80
- @client.hset feature.key, to_field(gate, thing), 1
99
+ @client.hset feature_key, to_field(gate, thing), 1
81
100
  else
82
101
  unsupported_data_type gate.data_type
83
102
  end
@@ -93,13 +112,14 @@ module Flipper
93
112
  #
94
113
  # Returns true.
95
114
  def disable(feature, gate, thing)
115
+ feature_key = key_for(feature.key)
96
116
  case gate.data_type
97
117
  when :boolean
98
- @client.del feature.key
118
+ @client.del feature_key
99
119
  when :integer
100
- @client.hset feature.key, gate.key, thing.value.to_s
120
+ @client.hset feature_key, gate.key, thing.value.to_s
101
121
  when :set
102
- @client.hdel feature.key, to_field(gate, thing)
122
+ @client.hdel feature_key, to_field(gate, thing)
103
123
  else
104
124
  unsupported_data_type gate.data_type
105
125
  end
@@ -109,6 +129,10 @@ module Flipper
109
129
 
110
130
  private
111
131
 
132
+ def redis_sadd_returns_boolean?
133
+ @client.class.respond_to?(:sadd_returns_boolean) && @client.class.sadd_returns_boolean
134
+ end
135
+
112
136
  def read_many_features(features)
113
137
  docs = docs_for(features)
114
138
  result = {}
@@ -119,20 +143,20 @@ module Flipper
119
143
  end
120
144
 
121
145
  def read_feature_keys
122
- @client.smembers(FeaturesKey).to_set
146
+ @client.smembers(features_key).to_set
123
147
  end
124
148
 
125
149
  # Private: Gets a hash of fields => values for the given feature.
126
150
  #
127
151
  # Returns a Hash of fields => values.
128
- def doc_for(feature)
129
- @client.hgetall(feature.key)
152
+ def doc_for(feature, pipeline: @client)
153
+ pipeline.hgetall(key_for(feature.key))
130
154
  end
131
155
 
132
156
  def docs_for(features)
133
- @client.pipelined do
157
+ @client.pipelined do |pipeline|
134
158
  features.each do |feature|
135
- doc_for(feature)
159
+ doc_for(feature, pipeline: pipeline)
136
160
  end
137
161
  end
138
162
  end
@@ -178,3 +202,10 @@ module Flipper
178
202
  end
179
203
  end
180
204
  end
205
+
206
+ Flipper.configure do |config|
207
+ config.adapter do
208
+ client = Redis.new(url: ENV["FLIPPER_REDIS_URL"] || ENV["REDIS_URL"])
209
+ Flipper::Adapters::Redis.new(client)
210
+ end
211
+ end
@@ -148,7 +148,7 @@ module Flipper
148
148
  return [] if keys.empty?
149
149
 
150
150
  cache_keys = keys.map { |key| key_for(key) }
151
- @cache.mget(cache_keys).map do |value|
151
+ @cache.mget(*cache_keys).map do |value|
152
152
  value ? Marshal.load(value) : nil
153
153
  end
154
154
  end
@@ -1,3 +1,3 @@
1
1
  module Flipper
2
- VERSION = '0.20.4'.freeze
2
+ VERSION = '1.0.0'.freeze
3
3
  end
@@ -1,7 +1,5 @@
1
- require 'helper'
2
1
  require 'flipper/adapters/operation_logger'
3
2
  require 'flipper/adapters/redis_cache'
4
- require 'flipper/spec/shared_adapter_specs'
5
3
 
6
4
  RSpec.describe Flipper::Adapters::RedisCache do
7
5
  let(:client) do
@@ -19,7 +17,9 @@ RSpec.describe Flipper::Adapters::RedisCache do
19
17
  subject { adapter }
20
18
 
21
19
  before do
22
- client.flushdb
20
+ skip_on_error(Redis::CannotConnectError, 'Redis not available') do
21
+ client.flushdb
22
+ end
23
23
  end
24
24
 
25
25
  it_should_behave_like 'a flipper adapter'
@@ -1,6 +1,4 @@
1
- require 'helper'
2
1
  require 'flipper/adapters/redis'
3
- require 'flipper/spec/shared_adapter_specs'
4
2
 
5
3
  RSpec.describe Flipper::Adapters::Redis do
6
4
  let(:client) do
@@ -8,14 +6,50 @@ RSpec.describe Flipper::Adapters::Redis do
8
6
 
9
7
  options[:url] = ENV['REDIS_URL'] if ENV['REDIS_URL']
10
8
 
9
+ Redis.raise_deprecations = true
11
10
  Redis.new(options)
12
11
  end
13
12
 
14
13
  subject { described_class.new(client) }
15
14
 
16
15
  before do
17
- client.flushdb
16
+ skip_on_error(Redis::CannotConnectError, 'Redis not available') do
17
+ client.flushdb
18
+ end
18
19
  end
19
20
 
20
21
  it_should_behave_like 'a flipper adapter'
22
+
23
+ it 'configures itself on load' do
24
+ Flipper.configuration = nil
25
+ Flipper.instance = nil
26
+
27
+ silence { load 'flipper/adapters/redis.rb' }
28
+
29
+ expect(Flipper.adapter.adapter).to be_a(Flipper::Adapters::Redis)
30
+ end
31
+
32
+ describe 'with a key_prefix' do
33
+ let(:subject) { described_class.new(client, key_prefix: "lockbox:") }
34
+ let(:feature) { Flipper::Feature.new(:search, subject) }
35
+
36
+ it_should_behave_like 'a flipper adapter'
37
+
38
+ it 'namespaces feature-keys' do
39
+ subject.add(feature)
40
+
41
+ expect(client.smembers("flipper_features")).to eq([])
42
+ expect(client.exists?("search")).to eq(false)
43
+ expect(client.smembers("lockbox:flipper_features")).to eq(["search"])
44
+ expect(client.hgetall("lockbox:search")).not_to eq(nil)
45
+ end
46
+
47
+ it "can remove namespaced keys" do
48
+ subject.add(feature)
49
+ expect(client.smembers("lockbox:flipper_features")).to eq(["search"])
50
+
51
+ subject.remove(feature)
52
+ expect(client.smembers("lockbox:flipper_features")).to be_empty
53
+ end
54
+ end
21
55
  end
@@ -9,6 +9,8 @@ class RedisCacheTest < MiniTest::Test
9
9
  @cache = Redis.new(url: url).tap(&:flushdb)
10
10
  memory_adapter = Flipper::Adapters::Memory.new
11
11
  @adapter = Flipper::Adapters::RedisCache.new(memory_adapter, @cache)
12
+ rescue Redis::CannotConnectError
13
+ ENV['CI'] ? raise : skip('Reids not available')
12
14
  end
13
15
 
14
16
  def teardown
@@ -8,5 +8,7 @@ class RedisTest < MiniTest::Test
8
8
  url = ENV.fetch('REDIS_URL', 'redis://localhost:6379')
9
9
  client = Redis.new(url: url).tap(&:flushdb)
10
10
  @adapter = Flipper::Adapters::Redis.new(client)
11
+ rescue Redis::CannotConnectError
12
+ ENV['CI'] ? raise : skip('Redis not available')
11
13
  end
12
14
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flipper-redis
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.20.4
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Nunemaker
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-06 00:00:00.000000000 Z
11
+ date: 2023-08-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: flipper
@@ -16,42 +16,40 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.20.4
19
+ version: 1.0.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.20.4
26
+ version: 1.0.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: redis
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '2.2'
33
+ version: '3.0'
34
34
  - - "<"
35
35
  - !ruby/object:Gem::Version
36
- version: '5'
36
+ version: '6'
37
37
  type: :runtime
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
40
40
  requirements:
41
41
  - - ">="
42
42
  - !ruby/object:Gem::Version
43
- version: '2.2'
43
+ version: '3.0'
44
44
  - - "<"
45
45
  - !ruby/object:Gem::Version
46
- version: '5'
47
- description:
48
- email:
49
- - nunemaker@gmail.com
46
+ version: '6'
47
+ description:
48
+ email: support@flippercloud.io
50
49
  executables: []
51
50
  extensions: []
52
51
  extra_rdoc_files: []
53
52
  files:
54
- - docs/redis/README.md
55
53
  - examples/redis/basic.rb
56
54
  - examples/redis/internals.rb
57
55
  - examples/redis/namespaced.rb
@@ -64,12 +62,16 @@ files:
64
62
  - spec/flipper/adapters/redis_spec.rb
65
63
  - test/adapters/redis_cache_test.rb
66
64
  - test/adapters/redis_test.rb
67
- homepage: https://github.com/jnunemaker/flipper
65
+ homepage: https://www.flippercloud.io/docs/adapters/redis
68
66
  licenses:
69
67
  - MIT
70
68
  metadata:
71
- changelog_uri: https://github.com/jnunemaker/flipper/blob/master/Changelog.md
72
- post_install_message:
69
+ documentation_uri: https://www.flippercloud.io/docs
70
+ homepage_uri: https://www.flippercloud.io
71
+ source_code_uri: https://github.com/flippercloud/flipper
72
+ bug_tracker_uri: https://github.com/flippercloud/flipper/issues
73
+ changelog_uri: https://github.com/flippercloud/flipper/blob/main/Changelog.md
74
+ post_install_message:
73
75
  rdoc_options: []
74
76
  require_paths:
75
77
  - lib
@@ -84,8 +86,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
84
86
  - !ruby/object:Gem::Version
85
87
  version: '0'
86
88
  requirements: []
87
- rubygems_version: 3.0.3
88
- signing_key:
89
+ rubygems_version: 3.4.10
90
+ signing_key:
89
91
  specification_version: 4
90
92
  summary: Redis adapter for Flipper
91
93
  test_files:
data/docs/redis/README.md DELETED
@@ -1,103 +0,0 @@
1
- # Flipper Redis
2
-
3
- A [Redis](https://github.com/redis/redis-rb) adapter for [Flipper](https://github.com/jnunemaker/flipper).
4
-
5
- ## Installation
6
-
7
- Add this line to your application's Gemfile:
8
-
9
- gem 'flipper-redis'
10
-
11
- And then execute:
12
-
13
- $ bundle
14
-
15
- Or install it yourself with:
16
-
17
- $ gem install flipper-redis
18
-
19
- ## Usage
20
-
21
- ```ruby
22
- require 'flipper/adapters/redis'
23
- client = Redis.new
24
- adapter = Flipper::Adapters::Redis.new(client)
25
- flipper = Flipper.new(adapter)
26
- # profit...
27
- ```
28
-
29
- ## Internals
30
-
31
- Each feature is stored in a redis hash, which means getting a feature is single query.
32
-
33
- ```ruby
34
- require 'flipper/adapters/redis'
35
-
36
- client = Redis.new
37
- adapter = Flipper::Adapters::Redis.new(client)
38
- flipper = Flipper.new(adapter)
39
-
40
- # Register a few groups.
41
- Flipper.register(:admins) { |thing| thing.admin? }
42
- Flipper.register(:early_access) { |thing| thing.early_access? }
43
-
44
- # Create a user class that has flipper_id instance method.
45
- User = Struct.new(:flipper_id)
46
-
47
- flipper[:stats].enable
48
- flipper[:stats].enable_group :admins
49
- flipper[:stats].enable_group :early_access
50
- flipper[:stats].enable_actor User.new('25')
51
- flipper[:stats].enable_actor User.new('90')
52
- flipper[:stats].enable_actor User.new('180')
53
- flipper[:stats].enable_percentage_of_time 15
54
- flipper[:stats].enable_percentage_of_actors 45
55
-
56
- flipper[:search].enable
57
-
58
- print 'all keys: '
59
- pp client.keys
60
- # all keys: ["stats", "flipper_features", "search"]
61
- puts
62
-
63
- print "known flipper features: "
64
- pp client.smembers("flipper_features")
65
- # known flipper features: ["stats", "search"]
66
- puts
67
-
68
- puts 'stats keys'
69
- pp client.hgetall('stats')
70
- # stats keys
71
- # {"boolean"=>"true",
72
- # "groups/admins"=>"1",
73
- # "actors/25"=>"1",
74
- # "percentage_of_time"=>"15",
75
- # "percentage_of_actors"=>"45",
76
- # "groups/early_access"=>"1",
77
- # "actors/90"=>"1",
78
- # "actors/180"=>"1"}
79
- puts
80
-
81
- puts 'search keys'
82
- pp client.hgetall('search')
83
- # search keys
84
- # {"boolean"=>"true"}
85
- puts
86
-
87
- puts 'flipper get of feature'
88
- pp adapter.get(flipper[:stats])
89
- # flipper get of feature
90
- # {:boolean=>"true",
91
- # :groups=>#<Set: {"admins", "early_access"}>,
92
- # :actors=>#<Set: {"25", "90", "180"}>,
93
- # :percentage_of_actors=>"45",
94
- # :percentage_of_time=>"15"}
95
- ```
96
-
97
- ## Contributing
98
-
99
- 1. Fork it
100
- 2. Create your feature branch (`git checkout -b my-new-feature`)
101
- 3. Commit your changes (`git commit -am 'Added some feature'`)
102
- 4. Push to the branch (`git push origin my-new-feature`)
103
- 5. Create new Pull Request