Class: Trebuchet
- Inherits:
-
Object
show all
- Extended by:
- Forwardable
- Defined in:
- lib/trebuchet.rb,
lib/trebuchet/version.rb,
lib/trebuchet/strategy/stub.rb,
lib/trebuchet/feature/stubbing.rb
Defined Under Namespace
Modules: ActionController, Backend, Strategy
Classes: ActionControllerFilter, BackendError, BackendInitializationError, Error, Feature
Constant Summary
collapse
- SHA1 =
initialize a single one to save object allocations Todo perhaps choose a better hash instead of sha1
Digest::SHA1.new
- VERSION =
"0.12.1".freeze
Class Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
Constructor Details
#initialize(current_user, request = nil) ⇒ Trebuchet
Returns a new instance of Trebuchet.
136
137
138
139
140
|
# File 'lib/trebuchet.rb', line 136
def initialize(current_user, request = nil)
@current_user = current_user
@request = request
@result_cache = {}
end
|
Class Attribute Details
.exception_handler ⇒ Object
Returns the value of attribute exception_handler.
15
16
17
|
# File 'lib/trebuchet.rb', line 15
def exception_handler
@exception_handler
end
|
.threadsafe_state ⇒ Object
Also known as:
threadsafe_state?
Returns the value of attribute threadsafe_state.
16
17
18
|
# File 'lib/trebuchet.rb', line 16
def threadsafe_state
@threadsafe_state
end
|
Class Method Details
.aim(feature_name, *args) ⇒ Object
96
97
98
|
# File 'lib/trebuchet.rb', line 96
def self.aim(feature_name, *args)
Feature.find(feature_name).aim(*args)
end
|
.backend ⇒ Object
18
19
20
21
|
# File 'lib/trebuchet.rb', line 18
def backend
self.backend = :memory unless @backend
@backend
end
|
.current ⇒ Object
57
58
59
60
|
# File 'lib/trebuchet.rb', line 57
def current
state.current ||= current_block.call if current_block.respond_to?(:call)
state.current || new(nil) end
|
.current=(other) ⇒ Object
53
54
55
|
# File 'lib/trebuchet.rb', line 53
def current=(other)
state.current = other
end
|
.define_request_aware_strategy(name, &block) ⇒ Object
.define_strategy(name, &block) ⇒ Object
108
109
110
|
# File 'lib/trebuchet.rb', line 108
def self.define_strategy(name, &block)
Strategy::Custom.define(name, block)
end
|
.dismantle(feature_name) ⇒ Object
100
101
102
|
# File 'lib/trebuchet.rb', line 100
def self.dismantle(feature_name)
Feature.find(feature_name).dismantle
end
|
.dismantle_stubs ⇒ Object
104
105
106
|
# File 'lib/trebuchet.rb', line 104
def self.dismantle_stubs
Feature.dismantle_stubs
end
|
.export ⇒ Object
171
172
173
174
175
176
177
|
# File 'lib/trebuchet.rb', line 171
def self.export
{}.tap do |features|
Trebuchet.backend.get_feature_names.map do |fn|
features[fn] = self.feature(fn).strategy.export
end
end
end
|
.feature(name) ⇒ Object
132
133
134
|
# File 'lib/trebuchet.rb', line 132
def self.feature(name)
Feature.find(name)
end
|
.history(include_archived = false) ⇒ Object
179
180
181
182
183
184
|
# File 'lib/trebuchet.rb', line 179
def self.history(include_archived = false)
return [] unless Trebuchet.backend.respond_to?(:get_all_history)
Trebuchet.backend.get_all_history(include_archived).map do |row|
[Time.at(row.first), Feature.find(row.last)]
end
end
|
.initialize_logs ⇒ Object
Logging done at class level TODO: split by user identifier so instance can return scoped to one user (in case multiple users have user.trebuchet called)
40
41
42
|
# File 'lib/trebuchet.rb', line 40
def initialize_logs
state.logs = {}
end
|
.log(feature_name, result) ⇒ Object
44
45
46
47
|
# File 'lib/trebuchet.rb', line 44
def log(feature_name, result)
initialize_logs if state.logs.nil?
logs[feature_name] = result
end
|
.logs ⇒ Object
49
50
51
|
# File 'lib/trebuchet.rb', line 49
def logs
state.logs
end
|
.reset_current! ⇒ Object
62
63
64
|
# File 'lib/trebuchet.rb', line 62
def reset_current!
self.current = nil
end
|
.set_backend(backend_type, *args) ⇒ Object
Also known as:
backend=
23
24
25
26
27
28
29
30
|
# File 'lib/trebuchet.rb', line 23
def set_backend(backend_type, *args)
if backend_type.is_a?(Symbol)
require "trebuchet/backend/#{backend_type}"
@backend = Backend.lookup(backend_type).new(*args)
elsif backend_type.class.name =~ /Trebuchet::Backend/
@backend = backend_type
end
end
|
.state ⇒ Object
state is a representation of the current context of Trebuchet such as current and current_proc, which are expected to be different between threads or fibers. exception_handler and backend are not included in this state object as they are not expected to change from fiber to fiber or request to request, therefore they must be thread/fibersafe on their own accord.
75
76
77
78
79
80
81
|
# File 'lib/trebuchet.rb', line 75
def state
if threadsafe_state?
Thread.current[thread_local_key] ||= State.new
else
@state ||= State.new
end
end
|
.state=(new_state) ⇒ Object
83
84
85
86
87
88
89
|
# File 'lib/trebuchet.rb', line 83
def state=(new_state)
if threadsafe_state?
Thread.current[thread_local_key] = new_state
else
@state = new_state
end
end
|
.thread_local_key ⇒ Object
66
67
68
|
# File 'lib/trebuchet.rb', line 66
def thread_local_key
:trebuchet_state
end
|
.use_with_rails! ⇒ Object
.visitor_id=(id_or_proc) ⇒ Object
116
117
118
119
120
121
122
123
124
|
# File 'lib/trebuchet.rb', line 116
def self.visitor_id=(id_or_proc)
if id_or_proc.is_a?(Proc)
state.visitor_id = id_or_proc
elsif id_or_proc.is_a?(Integer)
state.visitor_id = proc { |request| id_or_proc }
else
state.visitor_id = nil
end
end
|
Instance Method Details
#handle_exception(exception, feature = nil) ⇒ Object
163
164
165
166
167
168
169
|
# File 'lib/trebuchet.rb', line 163
def handle_exception(exception, feature = nil)
if self.class.exception_handler.is_a?(Proc)
argc = self.class.exception_handler.arity
argc = 3 if argc < 0
self.class.exception_handler.call *[exception, feature, self][0,argc]
end
end
|
#launch(feature, &block) ⇒ Object
142
143
144
145
146
|
# File 'lib/trebuchet.rb', line 142
def launch(feature, &block)
if launch?(feature)
yield if block_given?
end
end
|
#launch?(feature) ⇒ Boolean
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
# File 'lib/trebuchet.rb', line 148
def launch?(feature)
result = @result_cache[feature]
if result.nil?
result = @result_cache[feature] =
!!Feature.find(feature).launch_at?(@current_user, @request)
Trebuchet.log(feature, result)
end
result
rescue => e
handle_exception(e, feature)
return false
end
|