app_mode 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "http://rubygems.org"
2
+
3
+ group :rake do
4
+ gem 'rake', '~> 0.8.7'
5
+ end
@@ -0,0 +1,10 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ rake (0.8.7)
5
+
6
+ PLATFORMS
7
+ ruby
8
+
9
+ DEPENDENCIES
10
+ rake (~> 0.8.7)
data/README ADDED
@@ -0,0 +1,151 @@
1
+ == Welcome to AppMode
2
+
3
+ AppMode provides easy management of "states". This gem can be used to indicate
4
+ the state that a class, module, library, script, or application is running in.
5
+
6
+ == Getting Started
7
+
8
+ 1. Install AppMode at the command prompt if you haven't yet:
9
+
10
+ gem install app_mode
11
+
12
+ 2. Require the gem in your gemfile:
13
+
14
+ gem 'app_mode', '~> 0.0.1'
15
+
16
+ 3. Require the gem wherever you need state management:
17
+
18
+ require 'app_mode'
19
+
20
+ == Usage
21
+
22
+ There are two ways to use this gem.
23
+
24
+ 1. Create an object that handles the state of the module, class, or application:
25
+
26
+ This is the recommended method for managing the states of gems or libraries.
27
+ The reason is that the second method is global and changing the state in
28
+ a gem or library means the state will change in the application, too.
29
+ Therefore, it is better to localize the state to the gem or library.
30
+
31
+ See notes below on the :dynamic state, which is the default.
32
+
33
+ my_mode = AppMode.new
34
+
35
+ my_mode.state = :test
36
+
37
+ if my_mode == :development
38
+ # Development code.
39
+ end
40
+
41
+ if my_mode.test
42
+ # Test code.
43
+ end
44
+
45
+ Or specify the state you want to use when initializing the object:
46
+
47
+ my_mode = AppMode.new(:development)
48
+
49
+ If you would like to use states other than those provided, you are free
50
+ to do so:
51
+
52
+ my_mode = AppMode.new(:blue, [:red, :yellow, :green, :blue])
53
+
54
+ my_mode.state = :yellow
55
+
56
+ if my_mode.green
57
+ # Green code.
58
+ end
59
+
60
+ The :dynamic state is still valid with custom states:
61
+
62
+ my_mode = AppMode.new(:dynamic, [:red, :yellow, :green, :blue])
63
+
64
+ 2. Use the class methods:
65
+ This method is really only recommended for the end application. The initial
66
+ state will be set dynamically, so there is nothing to do except use it.
67
+ Only the default states (see "A Word on States" below) are available
68
+ using this method.
69
+
70
+ if AppMode.state == :development
71
+ # Development code.
72
+ end
73
+
74
+ AppMode.state = :test
75
+
76
+ if AppMode.test
77
+ # Test code.
78
+ end
79
+
80
+ == Usage in libraries/gems
81
+
82
+ The following method is recommended for use in libraries or gems:
83
+
84
+ module MyModule
85
+ MyModuleMode = AppMode.new
86
+ end
87
+
88
+ or
89
+
90
+ class MyClass
91
+ MyClassMode = AppMode.new
92
+ end
93
+
94
+ == A Word on States
95
+
96
+ * AppMode assumes the following default "states":
97
+
98
+ :development
99
+
100
+ :test
101
+
102
+ :rake
103
+
104
+ :production
105
+
106
+ * There is a fifth state (:dynamic), which will tell AppMode to determine
107
+ the state by examining the stack trace. It is only available when initializing
108
+ a new AppMode object and assumes that the first state is 'development', the
109
+ second is 'test', the third is 'rake', and the last one (not the fourth) is
110
+ 'production'. If less than four states are specified, the last one will be
111
+ used for multiple states. For example, if the states specified are
112
+ [:orange, :apple, :grape], :grape will be used for both rake and production.
113
+
114
+ * Only states in the list when the AppMode object were created are valid.
115
+ For example, the following code will generate errors:
116
+
117
+ my_mode = AppMode.new(:blue, [:red, :green]) #=> RuntimeError: Invalid environment setting: 'blue'.
118
+
119
+ my_mode = AppMode.new(:dynamic, [:red, :green])
120
+
121
+ my_mode.state = :development #=> RuntimeError: Invalid environment setting: 'development'.
122
+
123
+ if my_mode.blue #=> RuntimeError: Invalid environment setting: 'blue'.
124
+ # Blue code.
125
+ end
126
+
127
+ * If you are unsure that a state is in the list, there are two ways to check:
128
+
129
+ Check for inclusion in the array of valid states:
130
+
131
+ my_mode = AppMode.new(:red, [:red, :green])
132
+
133
+ if my_mode.valid_states.include?(:purple) && my_mode.purple
134
+ # Purple code.
135
+ end
136
+
137
+ Use equivalency:
138
+
139
+ my_mode = AppMode.new(:red, [:red, :green])
140
+
141
+ if my_mode.state == :purple
142
+ # Purple code.
143
+ end
144
+
145
+ == Additional Documentation
146
+
147
+ rake rdoc:app
148
+
149
+ == License
150
+
151
+ AppMode is released under the GPLv3 license.
@@ -0,0 +1,24 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'app_mode'
3
+ s.version = '0.0.1'
4
+
5
+ s.summary = 'Application state management.'
6
+ s.description = 'AppMode provides state management for ' +
7
+ 'modules, classes, libraries, and applications.'
8
+
9
+ s.author = 'Travis Herrick'
10
+ s.email = 'tthetoad@gmail.com'
11
+ s.homepage = 'http://www.bitbucket.org/ToadJamb/gems_app_mode'
12
+
13
+ s.license = 'GPLV3'
14
+
15
+ s.extra_rdoc_files << 'README'
16
+
17
+ s.require_paths = ['lib']
18
+ s.files = Dir['lib/**/*.rb', '*']
19
+ s.test_files = Dir['test/**/*.rb']
20
+
21
+ s.add_development_dependency 'rake', '~> 0.8.7'
22
+
23
+ s.has_rdoc = true
24
+ end
@@ -0,0 +1,3 @@
1
+ gem_name = File.basename(__FILE__, '.rb')
2
+
3
+ require_relative File.join(gem_name, gem_name)
@@ -0,0 +1,184 @@
1
+ # This file contains a class to manage information about the mode that the
2
+ # executing code is running in.
3
+
4
+ #--
5
+ ################################################################################
6
+ # Copyright (C) 2011 Travis Herrick #
7
+ ################################################################################
8
+ # #
9
+ # \v^V,^!v\^/ #
10
+ # ~% %~ #
11
+ # { _ _ } #
12
+ # ( * - ) #
13
+ # | / | #
14
+ # \ _, / #
15
+ # \__.__/ #
16
+ # #
17
+ ################################################################################
18
+ # This program is free software: you can redistribute it #
19
+ # and/or modify it under the terms of the GNU General Public License #
20
+ # as published by the Free Software Foundation, #
21
+ # either version 3 of the License, or (at your option) any later version. #
22
+ # #
23
+ # Commercial licensing may be available for a fee under a different license. #
24
+ ################################################################################
25
+ # This program is distributed in the hope that it will be useful, #
26
+ # but WITHOUT ANY WARRANTY; #
27
+ # without even the implied warranty of MERCHANTABILITY #
28
+ # or FITNESS FOR A PARTICULAR PURPOSE. #
29
+ # See the GNU General Public License for more details. #
30
+ # #
31
+ # You should have received a copy of the GNU General Public License #
32
+ # along with this program. If not, see <http://www.gnu.org/licenses/>. #
33
+ ################################################################################
34
+ #++
35
+
36
+ # This class manages the mode that the executing code is running in.
37
+ class AppMode
38
+ attr_reader :state, :valid_states
39
+
40
+ # Tracks a global mode setting.
41
+ @@mode = nil
42
+
43
+ class << self
44
+ # Override the send method.
45
+ #
46
+ # This was implemented to cover the case where test is used as a state.
47
+ # In that case, the default behavior was to call the private
48
+ # test method from Kernel. This prevents that behavior in cases where a
49
+ # public method is available via method_missing in this class.
50
+ def send(method, *args)
51
+ return method_missing(method, *args) if respond_to_missing?(method, false)
52
+ super
53
+ end
54
+
55
+ # Initializes the global mode setting.
56
+ def setup(*args)
57
+ @@mode = self.new(*args)
58
+ end
59
+
60
+ ########################################################################
61
+ private
62
+ ########################################################################
63
+
64
+ # Passes missing methods on to the instance.
65
+ def method_missing(method, *args, &block)
66
+ setup unless @@mode
67
+ @@mode.send method, *args
68
+ end
69
+
70
+ # Ensure that the object knows what it can respond to via method_missing.
71
+ # ==== Input
72
+ # [method : Symbol] The method to check for a response to.
73
+ # [include_private : Boolean] Whether to include private methods.
74
+ # ==== Output
75
+ # [Boolean] Whether the object will respond to the specified method.
76
+ def respond_to_missing?(method, include_private)
77
+ return true if @@mode.respond_to?(method, include_private)
78
+ super
79
+ end
80
+ end
81
+
82
+ # Constructor.
83
+ # ==== Input
84
+ # [env : Symbol] The environment that the mode should be set to.
85
+ # [valid_states : Array : (:development, :test, :production)] Valid states.
86
+ # ==== Notes
87
+ # <tt>env</tt> must be a member of <tt>states</tt>.
88
+ # ==== Examples
89
+ # Mode.new #=> <Mode @state=:production, @valid_states=[:development, :test, :production]>
90
+ # Mode.new(:test) #=> <Mode @state=:test, @valid_states=[:development, :test, :production]>
91
+ # Mode.new(:dev, [:abc, :dev]) #=> <Mode @state=:dev, @valid_states=[:abc, :dev]>
92
+ def initialize(
93
+ state = :dynamic,
94
+ valid_states = [:development, :test, :rake, :production])
95
+ @state = state
96
+ @valid_states = valid_states
97
+ set_state @state
98
+ end
99
+
100
+ # Sets the environment instance variable.
101
+ # ==== Input
102
+ # [value : Symbol] The value that will be used for the environment.
103
+ def state=(value)
104
+ set_state value
105
+ end
106
+
107
+ # Override the send method.
108
+ #
109
+ # This was implemented to cover the case where test is used as a state.
110
+ # In that case, the default behavior was to call the private
111
+ # test method from Kernel. This prevents that behavior in cases where a
112
+ # public method is available via method_missing in this class.
113
+ def send(method, *args)
114
+ return method_missing(method, *args) if respond_to_missing?(method, false)
115
+ super
116
+ end
117
+
118
+ ############################################################################
119
+ private
120
+ ############################################################################
121
+
122
+ # Returns the appropriate state to use when setting the state dynamically.
123
+ # ==== Output
124
+ # [Symbol] The state that should be used when setting the state dynamically.
125
+ def dynamic_state
126
+ call = origin
127
+ return @valid_states[0] unless call.sub(/^\.\//, '').match(/\//)
128
+ return @valid_states[1] if call.match(/rake_test_loader\.rb/)
129
+ return @valid_states[2] if call.match(%r[/bin/rake])
130
+ return @valid_states.last
131
+ end
132
+
133
+ # Returns the current working directory.
134
+ # ==== Notes
135
+ # This method is overridden during tests.
136
+ def getwd
137
+ Dir.getwd
138
+ end
139
+
140
+ # Returns the first call in the stack.
141
+ # ==== Output
142
+ # [String] The file that made the first call in the stack.
143
+ # ==== Notes
144
+ # This method is overridden during tests.
145
+ def origin
146
+ caller.last
147
+ end
148
+
149
+ # Allows the getting of the mode.
150
+ # ==== Input
151
+ # [method : Symbol] The method that was called.
152
+ # [*args : Array] Any arguments that were passed in.
153
+ # [&block : Block] A block, if specified.
154
+ def method_missing(method, *args, &block)
155
+ return method == @state if respond_to_missing?(method, false)
156
+ super
157
+ end
158
+
159
+ # Ensure that the object knows what it can respond to via method_missing.
160
+ # ==== Input
161
+ # [method : Symbol] The method to check for a response to.
162
+ # [include_private : Boolean] Whether to include private methods.
163
+ # ==== Output
164
+ # [Boolean] Indicates whether the object will respond to the specified method.
165
+ def respond_to_missing?(method, include_private)
166
+ return true if @valid_states.include?(method)
167
+ super
168
+ end
169
+
170
+ # Sets the state.
171
+ # ==== Input
172
+ # [value : Symbol] The value to use for the state.
173
+ def set_state(value)
174
+ unless @valid_states.include?(value) || value == :dynamic
175
+ raise "Invalid environment setting: '#{value}'."
176
+ end
177
+
178
+ if value == :dynamic
179
+ @state = dynamic_state || @valid_states.last
180
+ else
181
+ @state = value
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,16 @@
1
+ root_path = File.expand_path(File.dirname(__FILE__))
2
+ require 'bundler'
3
+ Bundler.require :rake
4
+ require 'rake/testtask'
5
+ require 'rake/rdoctask'
6
+ require 'rake/clean'
7
+ require 'tempfile'
8
+
9
+ task :default => [:tests]
10
+
11
+ # Include any ruby files in the tasks folder.
12
+ task_files = Dir[File.join(root_path, 'tasks', '*.rb')]
13
+
14
+ task_files.each do |rake_file|
15
+ require rake_file
16
+ end
@@ -0,0 +1,289 @@
1
+ #--
2
+ ################################################################################
3
+ # Copyright (C) 2011 Travis Herrick #
4
+ ################################################################################
5
+ # #
6
+ # \v^V,^!v\^/ #
7
+ # ~% %~ #
8
+ # { _ _ } #
9
+ # ( * - ) #
10
+ # | / | #
11
+ # \ _, / #
12
+ # \__.__/ #
13
+ # #
14
+ ################################################################################
15
+ # This program is free software: you can redistribute it #
16
+ # and/or modify it under the terms of the GNU General Public License #
17
+ # as published by the Free Software Foundation, #
18
+ # either version 3 of the License, or (at your option) any later version. #
19
+ # #
20
+ # Commercial licensing may be available for a fee under a different license. #
21
+ ################################################################################
22
+ # This program is distributed in the hope that it will be useful, #
23
+ # but WITHOUT ANY WARRANTY; #
24
+ # without even the implied warranty of MERCHANTABILITY #
25
+ # or FITNESS FOR A PARTICULAR PURPOSE. #
26
+ # See the GNU General Public License for more details. #
27
+ # #
28
+ # You should have received a copy of the GNU General Public License #
29
+ # along with this program. If not, see <http://www.gnu.org/licenses/>. #
30
+ ################################################################################
31
+ #++
32
+
33
+ require_relative 'require'
34
+
35
+ class AppModeTest < Test::Unit::TestCase
36
+ include AppModeSupport
37
+
38
+ def setup
39
+ @class.setup
40
+ super
41
+ end
42
+
43
+ def test_class_type
44
+ assert_equal AppMode, @class
45
+ end
46
+
47
+ ############################################################################
48
+ # Instance tests.
49
+ ############################################################################
50
+
51
+ def test_default_settings
52
+ create
53
+
54
+ assert_equal :production, @obj.state
55
+ assert_equal states(:default), @obj.valid_states
56
+
57
+ assert_true @obj.production
58
+ assert_false @obj.development
59
+ assert_false @obj.test
60
+ end
61
+
62
+ def test_setting_state
63
+ create :test
64
+
65
+ assert_equal :test, @obj.state
66
+ assert_true @obj.test
67
+
68
+ assert_nothing_raised { @obj.state = :development }
69
+
70
+ assert_equal :development, @obj.state
71
+ assert_true @obj.development
72
+ end
73
+
74
+ def test_new_object
75
+ create :test
76
+ assert_equal :test, @obj.state
77
+ assert_false @obj.development
78
+ assert_true @obj.test
79
+ assert_false @obj.rake
80
+ assert_false @obj.production
81
+
82
+ create :development
83
+ assert_equal :development, @obj.state
84
+ assert_true @obj.development
85
+ assert_false @obj.test
86
+ assert_false @obj.rake
87
+ assert_false @obj.production
88
+
89
+ create :production
90
+ assert_equal :production, @obj.state
91
+ assert_false @obj.development
92
+ assert_false @obj.test
93
+ assert_false @obj.rake
94
+ assert_true @obj.production
95
+
96
+ create :rake
97
+ assert_equal :rake, @obj.state
98
+ assert_false @obj.development
99
+ assert_false @obj.test
100
+ assert_true @obj.rake
101
+ assert_false @obj.production
102
+ end
103
+
104
+ def test_dynamic_state
105
+ assert_nothing_raised { create :dynamic }
106
+ assert_false @obj.development
107
+ assert_false @obj.test
108
+ assert_false @obj.rake
109
+ assert_true @obj.production
110
+
111
+ assert_nothing_raised { create :dynamic, states(:dev) }
112
+ assert_true @obj.dev_dev
113
+ assert_false @obj.dev_test
114
+ assert_false @obj.dev_rake
115
+ assert_false @obj.dev_prod
116
+
117
+ assert_nothing_raised { create :dynamic, states(:test) }
118
+ assert_false @obj.test_dev
119
+ assert_true @obj.test_test
120
+ assert_false @obj.test_rake
121
+ assert_false @obj.test_prod
122
+
123
+ assert_nothing_raised { create :dynamic, states(:rake) }
124
+ assert_false @obj.rake_dev
125
+ assert_false @obj.rake_test
126
+ assert_true @obj.rake_rake
127
+ assert_false @obj.rake_prod
128
+
129
+ assert_nothing_raised { create :dynamic, states(:prod) }
130
+ assert_false @obj.prod_dev
131
+ assert_false @obj.prod_test
132
+ assert_false @obj.prod_rake
133
+ assert_true @obj.prod_prod
134
+
135
+ assert_raise(NoMethodError) { @obj.dynamic }
136
+ assert_raise(NoMethodError) { @obj.test }
137
+ end
138
+
139
+ def test_dynamic_state_with_less_than_ideal_number_of_states
140
+ [
141
+ :dev,
142
+ :test,
143
+ :rake,
144
+ :prod,
145
+ ].each do |state|
146
+ state_array = states(state)[0..3]
147
+ end_value = state_array.length - 1
148
+
149
+ (0..end_value).each do |i|
150
+ assert_nothing_raised { create :dynamic, states(state)[0..i] }
151
+ case i
152
+ when 0
153
+ assert_true @obj.send("#{state}_dev")
154
+ when 1
155
+ case state
156
+ when :dev
157
+ assert_true @obj.dev_dev
158
+ else
159
+ assert_true @obj.send("#{state}_test")
160
+ end
161
+ when 2
162
+ case state
163
+ when :dev
164
+ assert_true @obj.dev_dev
165
+ when :test
166
+ assert_true @obj.test_test
167
+ else
168
+ assert_true @obj.send("#{state}_rake")
169
+ end
170
+ when 3
171
+ case state
172
+ when :dev
173
+ assert_true @obj.dev_dev
174
+ when :test
175
+ assert_true @obj.test_test
176
+ when :rake
177
+ assert_true @obj.rake_rake
178
+ when :prod
179
+ assert_true @obj.prod_prod
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end
185
+
186
+ def test_invalid_state
187
+ assert_raise(RuntimeError) { create :invalid }
188
+ assert_raise(NoMethodError) { create :test; @obj.invalid }
189
+ end
190
+
191
+ def test_respond_to
192
+ create :test
193
+
194
+ method_list.each_value do |method|
195
+ assert_respond_to @obj, method
196
+ end
197
+
198
+ states(:default).each do |method|
199
+ assert_respond_to @obj, method
200
+ end
201
+
202
+ assert_not_respond_to @obj, :invalid
203
+ end
204
+
205
+ # This test exists because of Kernel::test.
206
+ def test_send_method
207
+ create :test
208
+ assert_equal :test, @obj.send(:state)
209
+ assert_false @obj.send(:development)
210
+ assert_true @obj.send(:test)
211
+ assert_false @obj.send(:rake)
212
+ assert_false @obj.send(:production)
213
+
214
+ create :development, [:development, :production]
215
+ assert_equal :development, @obj.send(:state)
216
+ assert_true @obj.send(:development)
217
+ assert_false @obj.send(:production)
218
+ assert_raise(ArgumentError) { @obj.send(:test) }
219
+ end
220
+
221
+ ############################################################################
222
+ # Class tests.
223
+ ############################################################################
224
+
225
+ def test_class_default_settings
226
+ assert_equal :production, @class.state
227
+ assert_equal states(:default), @class.valid_states
228
+
229
+ assert_false @class.development
230
+ assert_false @class.test
231
+ assert_false @class.rake
232
+ assert_true @class.production
233
+ end
234
+
235
+ def test_class_setting_state
236
+ assert_nothing_raised { @class.state = :test }
237
+
238
+ assert_equal :test, @class.state
239
+ assert_true @class.test
240
+
241
+ assert_nothing_raised { @class.state = :development }
242
+
243
+ assert_equal :development, @class.state
244
+ assert_true @class.development
245
+ end
246
+
247
+ def test_class_invalid_state
248
+ assert_raise(RuntimeError) { @class.setup :invalid }
249
+ assert_raise(NoMethodError) { @class.invalid }
250
+ end
251
+
252
+ def test_class_respond_to
253
+ @class.state = :test
254
+
255
+ method_list.each_value do |method|
256
+ assert_respond_to @class, method
257
+ end
258
+
259
+ states(:default).each do |method|
260
+ assert_respond_to @class, method
261
+ end
262
+
263
+ assert_not_respond_to @class, :invalid
264
+ end
265
+
266
+ # This test exists because of Kernel::test.
267
+ def test_class_send_method
268
+ @class.state = :test
269
+ assert_equal :test, @class.send(:state)
270
+ assert_false @class.send(:development)
271
+ assert_true @class.send(:test)
272
+ assert_false @class.send(:rake)
273
+ assert_false @class.send(:production)
274
+
275
+ @class.setup :development, [:development, :production]
276
+ assert_equal :development, @class.send(:state)
277
+ assert_true @class.send(:development)
278
+ assert_false @class.send(:production)
279
+ assert_raise(ArgumentError) { @class.send(:test) }
280
+ end
281
+
282
+ ############################################################################
283
+ private
284
+ ############################################################################
285
+
286
+ def create(*args)
287
+ @obj = @class.new(*args)
288
+ end
289
+ end