sitehub 0.5.0.alpha3 → 0.5.0.alpha4

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
  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