app_mode 0.0.1

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