arturo 0.2.3.4 → 0.2.3.6

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -256,6 +256,20 @@ The latter can be used like so:
256
256
  widgets
257
257
  end
258
258
 
259
+ #### Outside a Controller
260
+
261
+ If you want to check availability outside of a controller or view (really
262
+ outside of something that has `Arturo::FeatureAvailability` mixed in), you
263
+ can ask either
264
+
265
+ Arturo.feature_enabled_for?(:foo, recipient)
266
+
267
+ or the slightly fancier
268
+
269
+ Arturo.foo_enabled_for?(recipient)
270
+
271
+ Both check whether the `foo` feature exists and is enabled for `recipient`.
272
+
259
273
  #### Caching
260
274
 
261
275
  **Note**: Arturo does not yet have caching support. Be very careful when
data/lib/arturo.rb CHANGED
@@ -3,8 +3,35 @@ module Arturo
3
3
  require 'arturo/special_handling'
4
4
  require 'arturo/feature_availability'
5
5
  require 'arturo/feature_management'
6
+ require 'arturo/feature_caching'
6
7
  require 'arturo/controller_filters'
7
8
  require 'arturo/range_form_support'
8
9
  require 'arturo/engine' if defined?(Rails) && Rails::VERSION::MAJOR == 2 && Rails::VERSION::MINOR == 3
9
10
 
11
+ class <<self
12
+
13
+ # Quick check for whether a feature is enabled for a recipient.
14
+ # @param [String, Symbol] feature_name
15
+ # @param [#id] recipient
16
+ # @return [true,false] whether the feature exists and is enabled for the recipient
17
+ def feature_enabled_for?(feature_name, recipient)
18
+ f = self::Feature.to_feature(feature_name)
19
+ f && f.enabled_for?(recipient)
20
+ end
21
+
22
+ ENABLED_FOR_METHOD_NAME = /^(\w+)_enabled_for\?$/
23
+
24
+ def respond_to?(symbol)
25
+ symbol.to_s =~ ENABLED_FOR_METHOD_NAME || super(symbol)
26
+ end
27
+
28
+ def method_missing(symbol, *args, &block)
29
+ if (args.length == 1 && match = ENABLED_FOR_METHOD_NAME.match(symbol.to_s))
30
+ feature_enabled_for?(match[1], args[0])
31
+ else
32
+ super(symbol, *args, &block)
33
+ end
34
+ end
35
+
36
+ end
10
37
  end
@@ -0,0 +1,81 @@
1
+ module Arturo
2
+
3
+ # To be extended by Arturo::Feature if you want to enable
4
+ # in-memory caching.
5
+ # NB: Arturo's feature caching only works when using
6
+ # Arturo::Feature.to_feature or when using the helper methods
7
+ # in Arturo and Arturo::FeatureAvailability.
8
+ # NB: if you have multiple application servers, you almost certainly
9
+ # want to clear this cache after each request:
10
+ #
11
+ # class ApplicationController < ActionController::Base
12
+ # after_filter { Arturo::Feature.clear_feature_cache }
13
+ # end
14
+ #
15
+ # Alternatively, you could redefine Arturo::Feature.feature_cache
16
+ # to use a shared cache like Memcached.
17
+ module FeatureCaching
18
+
19
+ def self.extended(base)
20
+ class <<base
21
+ alias_method_chain :to_feature, :caching
22
+ attr_accessor :cache_ttl, :feature_cache
23
+ end
24
+ base.cache_ttl = 0
25
+ base.feature_cache = Arturo::FeatureCaching::Cache.new
26
+ end
27
+
28
+ def caches_features?
29
+ self.cache_ttl.to_i > 0
30
+ end
31
+
32
+ # Wraps Arturo::Feature.to_feature with in-memory caching.
33
+ def to_feature_with_caching(feature_or_symbol)
34
+ if !self.caches_features?
35
+ return to_feature_without_caching(feature_or_symbol)
36
+ elsif (feature_or_symbol.kind_of?(Arturo::Feature))
37
+ feature_cache.write(feature_or_symbol.symbol, feature_or_symbol, :expires_in => cache_ttl)
38
+ feature_or_symbol
39
+ elsif (cached_feature = feature_cache.read(feature_or_symbol.to_sym))
40
+ cached_feature
41
+ elsif (f = to_feature_without_caching(feature_or_symbol))
42
+ feature_cache.write(f.symbol, f, :expires_in => cache_ttl)
43
+ f
44
+ end
45
+ end
46
+
47
+ protected
48
+
49
+ # Quack like a Rails cache.
50
+ class Cache
51
+ def initialize
52
+ @data = {} # of the form {key => [value, expires_at or nil]}
53
+ end
54
+ def read(name, options = nil)
55
+ name = name.to_s
56
+ value, expires_at = *@data[name]
57
+ if value && (expires_at.blank? || expires_at > Time.now)
58
+ value
59
+ else
60
+ nil
61
+ end
62
+ end
63
+ def write(name, value, options = nil)
64
+ name = name.to_s
65
+ expires_at = if options && options.respond_to?(:[]) && options[:expires_in]
66
+ Time.now + options.delete(:expires_in)
67
+ else
68
+ nil
69
+ end
70
+ value.freeze.tap do |val|
71
+ @data[name] = [value, expires_at]
72
+ end
73
+ end
74
+ def clear
75
+ @data.clear
76
+ end
77
+ end
78
+
79
+ end
80
+
81
+ end
@@ -0,0 +1,30 @@
1
+ Arturo.class_eval do
2
+
3
+ # Enable a feature; create it if necessary.
4
+ # For use in testing. Not auto-required on load. To load,
5
+ #
6
+ # require 'arturo/test_support'
7
+ #
8
+ # @param [Symbol, String] name the feature name
9
+ def enable_feature!(name)
10
+ feature = Arturo::Feature.find_by_symbol(name)
11
+ if feature
12
+ feature.update_attributes(:deployment_percentage => 100)
13
+ else
14
+ Arturo::Feature.create(:symbol => name, :deployment_percentage => 100)
15
+ end
16
+ end
17
+
18
+ # Disable a feature if it exists.
19
+ # For use in testing. Not auto-required on load. To load,
20
+ #
21
+ # require 'arturo/test_support'
22
+ #
23
+ # @param [Symbol, String] name the feature name
24
+ def disable_feature!(name)
25
+ if (feature = Arturo::Feature.find_by_symbol(name))
26
+ feature.update_attributes(:deployment_percentage => 0)
27
+ end
28
+ end
29
+
30
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arturo
3
3
  version: !ruby/object:Gem::Version
4
- hash: 91
4
+ hash: 95
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
9
  - 3
10
- - 4
11
- version: 0.2.3.4
10
+ - 6
11
+ version: 0.2.3.6
12
12
  platform: ruby
13
13
  authors:
14
14
  - James A. Rosen
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2010-11-04 00:00:00 -07:00
19
+ date: 2011-04-05 00:00:00 -07:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
@@ -108,6 +108,21 @@ dependencies:
108
108
  version: "1.3"
109
109
  type: :development
110
110
  version_requirements: *id006
111
+ - !ruby/object:Gem::Dependency
112
+ name: timecop
113
+ prerelease: false
114
+ requirement: &id007 !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ~>
118
+ - !ruby/object:Gem::Version
119
+ hash: 13
120
+ segments:
121
+ - 0
122
+ - 3
123
+ version: "0.3"
124
+ type: :development
125
+ version_requirements: *id007
111
126
  description: Deploy features incrementally to your users
112
127
  email: james.a.rosen@gmail.com
113
128
  executables: []
@@ -120,10 +135,12 @@ files:
120
135
  - lib/arturo/controller_filters.rb
121
136
  - lib/arturo/engine.rb
122
137
  - lib/arturo/feature_availability.rb
138
+ - lib/arturo/feature_caching.rb
123
139
  - lib/arturo/feature_factories.rb
124
140
  - lib/arturo/feature_management.rb
125
141
  - lib/arturo/range_form_support.rb
126
142
  - lib/arturo/special_handling.rb
143
+ - lib/arturo/test_support.rb
127
144
  - lib/arturo.rb
128
145
  - lib/generators/arturo/arturo_generator.rb
129
146
  - lib/generators/arturo/templates/arturo.css