sitehub 0.5.0.alpha3 → 0.5.0.alpha4

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
  SHA1:
3
- metadata.gz: 843f0e759d80716e875a4e9c10d7430fa3d3070a
4
- data.tar.gz: efb553e0b1090e8ec3fa9fe9a20c3474500dc28e
3
+ metadata.gz: 0ede66ca937a51aa4de571db5f3080113198429c
4
+ data.tar.gz: 91540d0d051530439cd2979ba054e5478cb215b6
5
5
  SHA512:
6
- metadata.gz: 81a3c977deca7ea18f198539f7d458ffb024dec97475be0d3928e9e3de519c58942c81614558fb02251ae2f457b39b8638050ec015505f45a877a834f20ac5ae
7
- data.tar.gz: 92576a7ed7130e047cd34ad2aaee32175d71b0fcbca6d9cb2fbf9f54554feb036c64c82dd9561bed5c23cc6acdc754c3dfd0ba8b898b5c6ab88b151d0d9f358b
6
+ metadata.gz: 8d1c08d30bcf5f0c95b20a7a49433ee214c65afa6d917eb04c5ca869d29fe3bff2bd8afce684b77f9920de2ee2f7f633797ba49b202cf6809fc3a2c25d8b4596
7
+ data.tar.gz: 9f2ce2edfb124e6b09b835986dd96a224bc7e403afbb20a808f19a0c5b0be83a5b044272b72680db17522b841ac3bbfbe03d982578d2666fd93db1b4f125a6e9
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sitehub (0.5.0.alpha3)
4
+ sitehub (0.5.0.alpha4)
5
5
  activesupport
6
6
  em-http-request
7
7
  em-synchrony
@@ -16,7 +16,7 @@ class SiteHub
16
16
  alias_method :add_backup, :add
17
17
 
18
18
  send(:define_method, :add) do |id, value, *args|
19
- raise DuplicateVersionException, UNIQUE_LABELS_MSG if self[id]
19
+ raise DuplicateVersionException, UNIQUE_LABELS_MSG if key?(id)
20
20
  add_backup id, value, *args
21
21
  end
22
22
  end
@@ -7,7 +7,7 @@ class SiteHub
7
7
  end
8
8
 
9
9
  def valid?
10
- !empty?
10
+ !keys.empty?
11
11
  end
12
12
 
13
13
  def resolve(id: nil, env: nil)
@@ -12,12 +12,6 @@ class SiteHub
12
12
  MAX = 100
13
13
  MIN = 0
14
14
 
15
- def initialize(hash = {})
16
- hash.each do |value, percentage|
17
- add(value.id, value, percentage)
18
- end
19
- end
20
-
21
15
  def add(id, value, percentage)
22
16
  raise InvalidSplitException, FIXNUM_ERR_MSG unless percentage.is_a?(Fixnum)
23
17
  upper_bound = lower_bound + percentage
@@ -28,20 +22,26 @@ class SiteHub
28
22
 
29
23
  def resolve(*args)
30
24
  random = rand(MAX)
31
- result = values.find { |split| random >= split.lower && random < split.upper }
25
+ result = _values.find { |split| random >= split.lower && random < split.upper }
32
26
  result ? result.value.resolve(*args) : nil
33
27
  end
34
28
 
35
29
  def transform(&block)
36
- values.each { |split| split.update_value(&block) }
30
+ _values.each { |split| split.update_value(&block) }
37
31
  end
38
32
 
39
33
  def [](key)
40
- key?(key) ? super(key).value : nil
34
+ key?(key) ? super(key).value : super(key)
35
+ end
36
+
37
+ alias _values values
38
+
39
+ def values
40
+ super().collect(&:value)
41
41
  end
42
42
 
43
43
  def valid?
44
- last = values.last
44
+ last = _values.last
45
45
  return true if last && last.upper == MAX
46
46
 
47
47
  warn(INVALID_SPILTS_MSG)
@@ -51,7 +51,7 @@ class SiteHub
51
51
  private
52
52
 
53
53
  def lower_bound
54
- values.empty? ? MIN : values.last.upper
54
+ _values.empty? ? MIN : _values.last.upper
55
55
  end
56
56
  end
57
57
  end
@@ -0,0 +1,37 @@
1
+ class SiteHub
2
+ class Identifier
3
+ attr_reader :id, :components
4
+
5
+ def initialize(id)
6
+ @components = id.to_s.split('|').collect(&:to_sym)
7
+ end
8
+
9
+ def child_label(label)
10
+ components.empty? ? label : "#{self}|#{label}"
11
+ end
12
+
13
+ def root
14
+ components.first
15
+ end
16
+
17
+ def sub_id
18
+ Identifier.new(components[1..-1].join('|'))
19
+ end
20
+
21
+ def valid?
22
+ !@components.empty?
23
+ end
24
+
25
+ def to_s
26
+ components.join('|')
27
+ end
28
+
29
+ def to_sym
30
+ to_s.to_sym
31
+ end
32
+
33
+ def ==(other)
34
+ other.respond_to?(:to_sym) && to_sym == other.to_sym
35
+ end
36
+ end
37
+ end
@@ -9,7 +9,7 @@ class SiteHub
9
9
 
10
10
  def initialize(app, id:, sitehub_cookie_name:, sitehub_cookie_path: nil)
11
11
  @app = app
12
- @id = id
12
+ @id = Identifier.new(id)
13
13
  @sitehub_cookie_name = sitehub_cookie_name
14
14
  @sitehub_cookie_path = sitehub_cookie_path
15
15
  end
@@ -23,9 +23,9 @@ class SiteHub
23
23
  def call(env)
24
24
  source_request = Rack::Request.new(env)
25
25
 
26
- forward_proxy = mapped_proxy(path: source_request.path, request: source_request)
26
+ route = mapped_route(path: source_request.path, request: source_request)
27
27
 
28
- forward_proxy.call(env)
28
+ route.call(env)
29
29
  end
30
30
 
31
31
  def init
@@ -46,7 +46,7 @@ class SiteHub
46
46
  end
47
47
  end
48
48
 
49
- def mapped_proxy(path:, request:)
49
+ def mapped_route(path:, request:)
50
50
  self[mapping(path)].resolve(id: request.cookies[sitehub_cookie_name], env: request.env)
51
51
  end
52
52
 
@@ -1,5 +1,7 @@
1
1
  require 'uuid'
2
2
  require 'sitehub/equality'
3
+ require 'sitehub/nil_route'
4
+ require 'sitehub/identifier'
3
5
  require 'sitehub/getter_setter_methods'
4
6
  require_relative 'collection/split_route_collection'
5
7
  require_relative 'rules'
@@ -14,16 +16,18 @@ class SiteHub
14
16
  class InvalidDefinitionException < Exception
15
17
  end
16
18
 
17
- INVALID_SPLIT_MSG = 'url must be defined if not supplying a block'.freeze
18
19
  ROUTES_WITH_SPLITS_MSG = 'you cant register routes and splits at the same level'.freeze
19
- INVALID_ROUTE_DEF_MSG = 'rule must be specified when supplying a block'.freeze
20
- IGNORING_URL_LABEL_MSG = 'Block supplied, ignoring URL and Label parameters'.freeze
20
+ INVALID_SPLIT_MSG = 'url must be defined if not supplying a block'.freeze
21
+ RULE_NOT_SPECIFIED_MSG = 'rule must be specified when supplying a block'.freeze
22
+ IGNORING_URL_MSG = 'Block supplied, ignoring URL parameter'.freeze
21
23
  URL_REQUIRED_MSG = 'URL must be supplied for splits and routes'.freeze
22
24
 
23
25
  class << self
24
26
  # TODO: support nest splits and routes
25
27
  def from_hash(hash, sitehub_cookie_name)
26
- new(sitehub_cookie_name: sitehub_cookie_name, sitehub_cookie_path: hash[:sitehub_cookie_path], mapped_path: hash[:path]) do
28
+ new(sitehub_cookie_name: sitehub_cookie_name,
29
+ sitehub_cookie_path: hash[:sitehub_cookie_path],
30
+ mapped_path: hash[:path]) do
27
31
  extend CollectionMethods
28
32
 
29
33
  collection(hash, :splits).each do |split|
@@ -44,11 +48,11 @@ class SiteHub
44
48
 
45
49
  transient :id
46
50
 
47
- getter_setters :default_proxy, :sitehub_cookie_path, :sitehub_cookie_name
51
+ getter_setters :sitehub_cookie_path, :sitehub_cookie_name
48
52
  attr_reader :mapped_path, :id
49
53
 
50
- def initialize(sitehub_cookie_name:, sitehub_cookie_path: nil, mapped_path:, rule: nil, &block)
51
- @id = UUID.generate(:compact)
54
+ def initialize(id: nil, sitehub_cookie_name:, sitehub_cookie_path: nil, mapped_path:, rule: nil, &block)
55
+ @id = Identifier.new(id)
52
56
  @mapped_path = mapped_path
53
57
  @sitehub_cookie_name = sitehub_cookie_name
54
58
  @sitehub_cookie_path = sitehub_cookie_path
@@ -62,32 +66,42 @@ class SiteHub
62
66
  raise InvalidDefinitionException unless valid?
63
67
  end
64
68
 
65
- def build
66
- if middleware?
67
- build_with_middleware
68
- build_default_with_middleware if default_proxy
69
- end
69
+ def add_route(label:, rule: nil, percentage: nil, url: nil, &block)
70
+ label = id.child_label(label)
71
+ route = if block
72
+ raise InvalidDefinitionException, RULE_NOT_SPECIFIED_MSG unless percentage || rule
73
+ warn(IGNORING_URL_MSG) if url
74
+ new(rule: rule, id: label, &block).build
75
+ else
76
+ raise InvalidDefinitionException, RULE_NOT_SPECIFIED_MSG unless url
77
+ forward_proxy(url: url, label: label, rule: rule)
78
+ end
70
79
 
71
- self
80
+ routes.add(label, route, percentage)
72
81
  end
73
82
 
74
- def default(url:)
75
- default_proxy(forward_proxy(label: :default, url: url))
83
+ def default_route
84
+ routes.default
76
85
  end
77
86
 
78
- def endpoints(collection = nil)
79
- return @endpoints || Collection::RouteCollection.new unless collection
87
+ def default_route?
88
+ !default_route.nil?
89
+ end
80
90
 
81
- raise InvalidDefinitionException, ROUTES_WITH_SPLITS_MSG if @endpoints && @endpoints != collection
82
- @endpoints = collection
91
+ def build
92
+ build_with_middleware if middleware?
93
+ self
94
+ end
95
+
96
+ def default(url:)
97
+ routes.default = forward_proxy(label: :default, url: url)
83
98
  end
84
99
 
85
100
  def forward_proxy(label:, url:, rule: nil)
86
101
  proxy = ForwardProxy.new(mapped_url: url, mapped_path: mapped_path)
87
102
 
88
- id = (label || UUID.generate(:compact)).to_sym
89
103
  Route.new(proxy,
90
- id: id,
104
+ id: label,
91
105
  sitehub_cookie_path: sitehub_cookie_path,
92
106
  sitehub_cookie_name: sitehub_cookie_name).tap do |wrapper|
93
107
  wrapper.rule(rule)
@@ -95,38 +109,34 @@ class SiteHub
95
109
  end
96
110
 
97
111
  def resolve(id: nil, env:)
98
- id = id.to_s.to_sym
99
- endpoints[id] || endpoints.resolve(id: id, env: env) || default_proxy
112
+ id = Identifier.new(id)
113
+ if id.valid? && (route = routes[id.root])
114
+ route.resolve(id: id.sub_id, env: env)
115
+ else
116
+ routes.resolve(env: env) || default_route
117
+ end
100
118
  end
101
119
 
102
- def route(url: nil, label: nil, rule: nil, &block)
103
- endpoint = if block
104
- raise InvalidDefinitionException, INVALID_ROUTE_DEF_MSG unless rule
105
- warn(IGNORING_URL_LABEL_MSG) if url || label
106
- new(rule: rule, &block).build
107
- else
108
- forward_proxy(url: url, label: label, rule: rule)
109
- end
110
-
111
- routes.add(endpoint.id, endpoint)
120
+ def route(url: nil, label:, rule: nil, &block)
121
+ routes(@routes)
122
+ add_route(label: label, rule: rule, url: url, &block)
112
123
  end
113
124
 
114
- def split(percentage:, url: nil, label: nil, &block)
115
- raise InvalidDefinitionException, INVALID_SPLIT_MSG unless block || url
125
+ def routes(collection = nil)
126
+ return @endpoints ||= Collection::RouteCollection.new unless collection
116
127
 
117
- proxy = if block
118
- warn(IGNORING_URL_LABEL_MSG) if url || label
119
- new(&block).build
120
- else
121
- forward_proxy(label: label, url: url)
122
- end
128
+ raise InvalidDefinitionException, ROUTES_WITH_SPLITS_MSG if @endpoints && !@endpoints.equal?(collection)
129
+ @endpoints = collection
130
+ end
123
131
 
124
- splits.add proxy.id, proxy, percentage
132
+ def split(percentage:, url: nil, label:, &block)
133
+ routes(@splits)
134
+ add_route(label: label, percentage: percentage, url: url, &block)
125
135
  end
126
136
 
127
137
  def valid?
128
- return true if default_proxy
129
- endpoints.valid?
138
+ return true if default_route?
139
+ routes.valid?
130
140
  end
131
141
 
132
142
  private
@@ -138,34 +148,24 @@ class SiteHub
138
148
  end
139
149
  end
140
150
 
141
- def build_default_with_middleware
142
- add_middleware_to_proxy(default_proxy)
143
- default_proxy.init
144
- end
145
-
146
151
  def build_with_middleware
147
- endpoints.values.each do |proxy|
148
- add_middleware_to_proxy(proxy)
149
- proxy.init
152
+ routes = routes().values.find_all { |route| route.is_a?(Route) }
153
+
154
+ routes << default_route if default_route?
155
+
156
+ routes.each do |route|
157
+ add_middleware_to_proxy(route)
158
+ route.init
150
159
  end
151
160
  end
152
161
 
153
- def new(rule: nil, &block)
154
- self.class.new(sitehub_cookie_name: sitehub_cookie_name,
162
+ def new(id:, rule: nil, &block)
163
+ self.class.new(id: id,
164
+ sitehub_cookie_name: sitehub_cookie_name,
165
+ sitehub_cookie_path: sitehub_cookie_path,
155
166
  mapped_path: mapped_path,
156
167
  rule: rule,
157
- &block).tap do |builder|
158
- builder.sitehub_cookie_name sitehub_cookie_name
159
- builder.sitehub_cookie_path sitehub_cookie_path
160
- end
161
- end
162
-
163
- def splits
164
- endpoints(@splits)
165
- end
166
-
167
- def routes
168
- endpoints(@routes)
168
+ &block)
169
169
  end
170
170
  end
171
171
  end
@@ -1,3 +1,3 @@
1
1
  class SiteHub
2
- VERSION = '0.5.0.alpha3'.freeze
2
+ VERSION = '0.5.0.alpha4'.freeze
3
3
  end
@@ -22,6 +22,14 @@ class SiteHub
22
22
  expect(subject).to be_a(Collection)
23
23
  end
24
24
 
25
+ describe '#[]' do
26
+ context 'key exists' do
27
+ end
28
+
29
+ context 'key does not exist' do
30
+ end
31
+ end
32
+
25
33
  describe '#add' do
26
34
  before do
27
35
  subject.add route_1.id, route_1, 50
@@ -32,8 +40,8 @@ class SiteHub
32
40
 
33
41
  it 'sets the selection boundary which is used to choose routes' do
34
42
  subject.add route_2.id, route_2, 50
35
- first = subject.values.first
36
- second = subject.values.last
43
+ first = subject._values.first
44
+ second = subject._values.last
37
45
 
38
46
  expect(first.lower).to eq(0)
39
47
  expect(first.upper).to eq(50)
@@ -117,5 +125,13 @@ class SiteHub
117
125
  end
118
126
  end
119
127
  end
128
+
129
+ describe '#values' do
130
+ it 'returns values contained inside splits' do
131
+ subject.add route_1.id, route_1, 50
132
+ subject.add route_2.id, route_2, 50
133
+ expect(subject.values).to eq([route_1, route_2])
134
+ end
135
+ end
120
136
  end
121
137
  end
@@ -26,6 +26,7 @@ class SiteHub
26
26
 
27
27
  inheritor.new
28
28
  end
29
+
29
30
  it 'raises an error' do
30
31
  duplicate = Struct.new(:id).new(1)
31
32
  subject.add(duplicate.id, duplicate)
@@ -123,7 +123,7 @@ class SiteHub
123
123
 
124
124
  it 'passes the block to the route constructor' do
125
125
  expected_route.split url: :endpoint, percentage: 100, label: :label
126
- expect(subject.routes['/app'].endpoints).to eq(expected_route.endpoints)
126
+ expect(subject.routes['/app'].routes).to eq(expected_route.routes)
127
127
  end
128
128
  end
129
129
  end
@@ -0,0 +1,89 @@
1
+ class SiteHub
2
+ describe Identifier do
3
+ subject(:valid_identifer) do
4
+ described_class.new(:root_id)
5
+ end
6
+
7
+ subject(:blank) do
8
+ described_class.new(nil)
9
+ end
10
+
11
+ describe '#initialize' do
12
+ context 'id supplied' do
13
+ it 'it returns a concatenated id' do
14
+ expect(valid_identifer.child_label(:label)).to eq('root_id|label')
15
+ end
16
+ end
17
+
18
+ context 'id not set' do
19
+ it 'it returns the given value' do
20
+ expect(blank.child_label(:label)).to eq(:label)
21
+ end
22
+ end
23
+ end
24
+
25
+ describe '#valid?' do
26
+ context 'has at least one component' do
27
+ it 'returns true' do
28
+ expect(valid_identifer).to be_valid
29
+ end
30
+ end
31
+
32
+ context 'does not have at least one component' do
33
+ it 'returns false' do
34
+ expect(blank).to_not be_valid
35
+ end
36
+ end
37
+ end
38
+
39
+ describe '#sub_id' do
40
+ context 'id contains more than one pipe seperated value' do
41
+ subject do
42
+ described_class.new('root|first|second')
43
+ end
44
+
45
+ it 'removes the first value in the list' do
46
+ expect(subject.sub_id).to eq(:'first|second')
47
+ end
48
+
49
+ it 'returns an object of type Identifier' do
50
+ expect(subject.sub_id).to be_a(described_class)
51
+ end
52
+ end
53
+ end
54
+
55
+ describe '#to_s' do
56
+ subject do
57
+ described_class.new(:root_id)
58
+ end
59
+ it 'returns the id as a string' do
60
+ expect(valid_identifer.to_s).to eq(:root_id.to_s)
61
+ end
62
+ end
63
+
64
+ describe '#to_sym' do
65
+ it 'returns the id as a string' do
66
+ expect(valid_identifer.to_sym).to eq(:root_id)
67
+ end
68
+ end
69
+
70
+ describe '#==' do
71
+ subject do
72
+ described_class.new(:root_id)
73
+ end
74
+
75
+ context 'other can be converted to a matching symbol' do
76
+ it 'returns true' do
77
+ expect(subject).to eq(:root_id)
78
+ expect(subject).to eq('root_id')
79
+ end
80
+ end
81
+
82
+ context 'other can not be converted to a matching symbol' do
83
+ it 'returns true' do
84
+ expect(subject).to_not eq('different')
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end