toggle 0.0.0.alpha → 1.0.0.rc

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ # Copy this file to ./config.yml or run the following command:
2
+ #
3
+ # $ toggle --copy-defaults [PATH]
4
+ #
5
+ # which will copy {config,key}{,.*}.default files in the given PATH to
6
+ # {config,key}{,.*} (removes .default extension)
7
+ #
8
+ # We're using the configuration conventions & setup:
9
+ # https://git.squareup.com/iacono/toggle#configuration-conventions--setup
10
+ #
11
+ # If you've set up your local variables, you should be able to copy and go!
12
+ #
13
+ # Otherwise, run:
14
+ #
15
+ # $ toggle --init-local
16
+ #
17
+ # And follow the instructions
18
+ :development:
19
+ :some: :development_setting
20
+
21
+ :production:
22
+ :some: :production_setting
23
+ # define any other config blocks that you want!
@@ -0,0 +1,15 @@
1
+ # Copy this file to ./key{.exts} or run the following command:
2
+ #
3
+ # $ toggle --copy-defaults [PATH]
4
+ #
5
+ # which will copy {config,key}{.exts}.default files in the given PATH to
6
+ # {config,key}{exts} (removes .default extension)
7
+ #
8
+ # You can toggle this file to use a particular config block you have
9
+ # set up. To view which top level blocks are available for a given key file,
10
+ # run:
11
+ #
12
+ # $ toggle --keys FILENAME
13
+ #
14
+ # where FILENAME is the name of a given toggle config file.
15
+ development # <= change "development" to whatever you'd like
data/lib/toggle.rb CHANGED
@@ -1,5 +1,78 @@
1
- require "toggle/version"
1
+ require 'toggle/version'
2
+ require 'toggle/compiler'
3
+ require 'toggle/parser'
4
+ require 'active_support/core_ext/hash/indifferent_access'
5
+ require 'active_support/core_ext/string'
2
6
 
3
- module Toggle
4
- # Your code goes here...
7
+ class Toggle
8
+ attr_writer :key
9
+ attr_accessor :key_parsers
10
+ attr_accessor :key_filepath
11
+ attr_accessor :config_parsers
12
+ attr_accessor :config_filepath
13
+
14
+ def initialize attributes = {}
15
+ attributes.keys.each do |attribute|
16
+ self.send "#{attribute}=", attributes[attribute]
17
+ end
18
+ end
19
+
20
+ def [] attribute
21
+ config[attribute]
22
+ end
23
+
24
+ def config_filepath= value
25
+ configs_dirty! unless @config_filepath.eql? value
26
+ @config_filepath = value
27
+ end
28
+
29
+ def key
30
+ (@key || key_from_file).try(:to_sym)
31
+ end
32
+
33
+ def config
34
+ configs[key]
35
+ end
36
+
37
+ def configs
38
+ return @configs if defined?(@configs) && configs_clean?
39
+
40
+ @configs = HashWithIndifferentAccess.new(
41
+ Toggle::Compiler.new(
42
+ config_filepath,
43
+ config_parsers
44
+ ).parsed_content
45
+ )
46
+ configs_clean!
47
+ @configs
48
+ end
49
+
50
+ def using temporary_key
51
+ return unless block_given?
52
+
53
+ previous_key, self.key = self.key, temporary_key
54
+ yield self
55
+ self.key = previous_key
56
+ end
57
+
58
+ private
59
+
60
+ def key_from_file
61
+ Toggle::Compiler.new(
62
+ key_filepath,
63
+ key_parsers
64
+ ).parsed_content if key_filepath
65
+ end
66
+
67
+ def configs_clean?
68
+ @configs_clean
69
+ end
70
+
71
+ def configs_dirty!
72
+ @configs_clean = false
73
+ end
74
+
75
+ def configs_clean!
76
+ @configs_clean = true
77
+ end
5
78
  end
@@ -0,0 +1,31 @@
1
+ class Toggle
2
+ class Compiler
3
+ class FileNotFound < RuntimeError; end
4
+
5
+ def initialize file, parsers = nil
6
+ @file = file
7
+ @parsers = parsers ? [*parsers] : file_extensions
8
+ end
9
+
10
+ def parsed_content
11
+ @parsers.reduce(raw_file_content) do |content, parser|
12
+ Toggle::Parser.for(parser).parse content if content
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def file_extensions
19
+ parts = File.basename(@file).split(".")
20
+ parts[1, parts.length - 1]
21
+ end
22
+
23
+ def raw_file_content
24
+ begin
25
+ File.read(@file).chomp
26
+ rescue ::Errno::ENOENT => e
27
+ raise FileNotFound.new e.message
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,17 @@
1
+ class Toggle
2
+ module Parser
3
+ class ParserNotFound < StandardError; end
4
+
5
+ def self.for type
6
+ case type.to_s.downcase
7
+ when 'yaml', 'yml'
8
+ require 'toggle/parser/yaml'
9
+ ::Toggle::Parser::YAML.new
10
+ else
11
+ raise ParserNotFound, <<-EOS
12
+ #{type} is not currently implemented. You should write it!
13
+ EOS
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ # YAML Parser handles erb parsing first, then loads the content to yaml
2
+ class Toggle
3
+ module Parser
4
+ class YAML
5
+ def parse content
6
+ require 'erb'
7
+ require 'yaml'
8
+ ::YAML.load(::ERB.new(content).result.chomp)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,3 +1,3 @@
1
- module Toggle
2
- VERSION = "0.0.0.alpha"
1
+ class Toggle
2
+ VERSION = "1.0.0.rc"
3
3
  end
data/script/ci ADDED
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env bash
2
+
3
+ bundler_version="1.1.4"
4
+
5
+ source "$HOME/.rvm/scripts/rvm"
6
+
7
+ function install_ruby_if_needed() {
8
+ echo "Checking for $1..."
9
+ if ! rvm list rubies | grep $1 > /dev/null; then
10
+ echo "Ruby not found $1..."
11
+ rvm install $1
12
+ fi
13
+ }
14
+
15
+ function switch_ruby() {
16
+ install_ruby_if_needed $1 && rvm use $1
17
+ }
18
+
19
+ function install_bundler_if_needed() {
20
+ echo "Checking for Bundler $bundler_version..."
21
+ if ! gem list --installed bundler --version "$bundler_version" > /dev/null; then
22
+ gem install bundler --version "$bundler_version"
23
+ fi
24
+ }
25
+
26
+ function update_gems_if_needed() {
27
+ echo "Installing gems..."
28
+ bundle check || bundle install
29
+ }
30
+
31
+ function run_tests() {
32
+ bundle exec rake
33
+ }
34
+
35
+ function prepare_and_run() {
36
+ switch_ruby $1 &&
37
+ install_bundler_if_needed &&
38
+ update_gems_if_needed &&
39
+ run_tests
40
+ }
41
+
42
+ prepare_and_run "1.9.3-p194"
data/spec/cli_spec.rb ADDED
@@ -0,0 +1,427 @@
1
+ require 'spec_helper'
2
+ require 'fileutils'
3
+
4
+ def clear_toggle_files_from path
5
+ Dir.glob(File.join(path, '*'), File::FNM_DOTMATCH).each do |file|
6
+ FileUtils.rm_f file if file =~ /((config|key)(\..*)?$|\.toggle\.local)/
7
+ end
8
+ end
9
+
10
+ describe "CLI" do
11
+ let(:test_dir) { File.join(File.expand_path('..', __FILE__), 'test', 'fixtures', 'cli') }
12
+
13
+ describe "--ensure-key" do
14
+ let(:default_key_file) { File.join(test_dir, 'key.yml.default') }
15
+ let(:key_file) { File.join(test_dir, 'key.yml') }
16
+ let(:content) { 'some_key' }
17
+
18
+ before :all do
19
+ clear_toggle_files_from test_dir
20
+ end
21
+
22
+ before :each do
23
+ %x(echo "#{content}" > #{default_key_file})
24
+ end
25
+
26
+ after :each do
27
+ clear_toggle_files_from test_dir
28
+ end
29
+
30
+ describe "when key does not exist" do
31
+ it "copies the default key to the actual" do
32
+ %x(./bin/toggle --ensure-key #{test_dir})
33
+ FileUtils.identical?(key_file, default_key_file).should == true
34
+ end
35
+ end
36
+
37
+ describe "when key already exists" do
38
+ let(:key_content) { 'existing_key' }
39
+
40
+ before do
41
+ %x(echo "#{key_content}" > #{key_file})
42
+ end
43
+
44
+ it "leaves the current key alone" do
45
+ %x(./bin/toggle --ensure-key #{test_dir})
46
+ File.read(key_file).chomp.should == key_content
47
+ end
48
+ end
49
+ end
50
+
51
+ describe "--copy-config-defaults" do
52
+ let(:default_config_file) { File.join(test_dir, 'config.yml.default') }
53
+ let(:actual_config_file) { File.join(test_dir, 'config.yml') }
54
+ let(:default_config_content) { 'DEFAULT CONFIG CONTENT' }
55
+
56
+ before :all do
57
+ clear_toggle_files_from test_dir
58
+ end
59
+
60
+ before :each do
61
+ %x(echo "#{default_config_content}" > #{default_config_file})
62
+ end
63
+
64
+ after :each do
65
+ clear_toggle_files_from test_dir
66
+ end
67
+
68
+ it "does not copy the key default" do
69
+ default_key_file = File.join(test_dir, 'key.yml.default')
70
+ actual_key_file = File.join(test_dir, 'key.yml')
71
+ default_key_content = 'some_key'
72
+
73
+ %x(echo "#{default_key_content}" > #{default_key_file})
74
+ %x(./bin/toggle --copy-config-defaults #{test_dir})
75
+ File.exists?(actual_key_file).should == false
76
+ end
77
+
78
+ describe "no config exists" do
79
+ it "copies the default config to the actual" do
80
+ %x(./bin/toggle --copy-config-defaults #{test_dir})
81
+ FileUtils.identical?(actual_config_file, default_config_file).should == true
82
+ end
83
+ end
84
+
85
+ describe "config is identical to default" do
86
+ before do
87
+ %x(cp #{default_config_file} #{actual_config_file})
88
+ end
89
+
90
+ it "leaves current config unchanged" do
91
+ %x(./bin/toggle --copy-config-defaults #{test_dir})
92
+ FileUtils.identical?(actual_config_file, default_config_file).should == true
93
+ end
94
+ end
95
+
96
+ describe "actual is present and different from default" do
97
+ let(:different_content) { "#{default_config_content} BUT DIFFERENT" }
98
+
99
+ before do
100
+ %x(echo "#{different_content}" > #{actual_config_file})
101
+ end
102
+
103
+ it "leaves current config unchanged when user responds with anything but 'y' words" do
104
+ %x(echo 'n' | ./bin/toggle --copy-config-defaults #{test_dir})
105
+ FileUtils.identical?(actual_config_file, default_config_file).should == false
106
+ end
107
+
108
+ it "replaces current config with default when user responds with 'y' words" do
109
+ %x(echo 'y' | ./bin/toggle --copy-config-defaults #{test_dir})
110
+ FileUtils.identical?(actual_config_file, default_config_file).should == true
111
+ File.read(actual_config_file).chomp.should == default_config_content
112
+ end
113
+ end
114
+ end
115
+
116
+ describe "--copy-defaults" do
117
+ let(:config_default_file) { File.join(test_dir, 'config.yml.default') }
118
+ let(:config_actual_file) { File.join(test_dir, 'config.yml') }
119
+ let(:config_default_content) { 'DEFAULT CONTENT' }
120
+ let(:key_default_file) { File.join(test_dir, 'key.yml.default') }
121
+ let(:key_actual_file) { File.join(test_dir, 'key.yml') }
122
+ let(:key_default_content) { 'DEFAULT CONTENT' }
123
+
124
+ before :all do
125
+ clear_toggle_files_from test_dir
126
+ end
127
+
128
+ before :each do
129
+ %x(echo "#{config_default_content}" > #{config_default_file})
130
+ %x(echo "#{key_default_content}" > #{key_default_file})
131
+ end
132
+
133
+ after :each do
134
+ clear_toggle_files_from test_dir
135
+ end
136
+
137
+ describe "copies default config and key file" do
138
+ it "copies each default file over to its appropriate location" do
139
+ %x(./bin/toggle --copy-defaults #{test_dir})
140
+ FileUtils.identical?(config_default_file, config_actual_file).should == true
141
+ FileUtils.identical?(key_default_file, key_actual_file).should == true
142
+ end
143
+ end
144
+
145
+ describe "actual is identical to default" do
146
+ before do
147
+ %x(cp #{config_default_file} #{config_actual_file})
148
+ end
149
+
150
+ it "leaves current file unchanged" do
151
+ %x(./bin/toggle --copy-defaults #{test_dir})
152
+ FileUtils.identical?(config_default_file, config_actual_file).should == true
153
+ end
154
+ end
155
+
156
+ describe "actual is present but has different content from default" do
157
+ let(:different_content) { "#{config_default_content} BUT DIFFERENT" }
158
+
159
+ before do
160
+ %x(echo "#{different_content}" > #{config_actual_file})
161
+ end
162
+
163
+ it "leaves current file unchanged when user responds with anything but 'y' words" do
164
+ %x(echo 'n' | ./bin/toggle --copy-defaults #{test_dir})
165
+ FileUtils.identical?(config_default_file, config_actual_file).should == false
166
+ File.read(config_actual_file).chomp.should == different_content
167
+ end
168
+
169
+ it "replaces current file with default when user responds with 'y' words" do
170
+ %x(echo 'y' | ./bin/toggle --copy-defaults #{test_dir})
171
+ FileUtils.identical?(config_default_file, config_actual_file).should == true
172
+ File.read(config_actual_file).chomp.should == config_default_content
173
+ end
174
+ end
175
+ end
176
+
177
+ describe "--keys" do
178
+ let(:config_file) { File.join(FIXTURES_PATH, 'config.yml') }
179
+
180
+ it "alerts the user if the file is not found" do
181
+ %x(./bin/toggle --keys /path/to/nothing).chomp.should == "toggle config file not found, please check specified path"
182
+ end
183
+
184
+ it "can be queried for the available keys from the commandline" do
185
+ %x(./bin/toggle --keys #{config_file}).chomp.should == "- local\n- remote"
186
+ end
187
+ end
188
+
189
+ describe "--values" do
190
+ let(:config_file) { File.join(FIXTURES_PATH, 'config.yml') }
191
+
192
+ it "alerts the user if the file is not found" do
193
+ %x(./bin/toggle --values /path/to/nothing).chomp.should == "toggle config file not found, please check specified path"
194
+ end
195
+
196
+ it "can be queried for the available keys from the commandline" do
197
+ %x(./bin/toggle --values #{config_file},local).should == <<-EOS.strip_heredoc
198
+ ---
199
+ :plain_attribute: local_plain_attribute_value
200
+ :erb_attribute: local_erb_attribute_value
201
+ EOS
202
+ end
203
+ end
204
+
205
+ describe "--init-local" do
206
+ let(:file) { File.join(test_dir, '.toggle.local') }
207
+
208
+ before :all do
209
+ clear_toggle_files_from test_dir
210
+ end
211
+
212
+ after :each do
213
+ clear_toggle_files_from test_dir
214
+ end
215
+
216
+ describe "file does not exist" do
217
+ it "adds .toggle.local with commons var placeholders" do
218
+ %x(./bin/toggle --init-local #{test_dir})
219
+ File.read(file).chomp.should == <<-EOS.strip_heredoc
220
+ # Add any variables that you'd like below.
221
+ #
222
+ # We've included a few suggestions, but please feel free
223
+ # to modify as needed.
224
+ #
225
+ # Make sure that you source this file in your ~/.bash_profile
226
+ # or ~/.bashrc (or whereever you'd like) via:
227
+ #
228
+ # if [ -s ~/.toggle.local ] ; then source ~/.toggle.local ; fi
229
+ export DATABASE_HOST=''
230
+ export DATABASE_NAME=''
231
+ export DATABASE_USERNAME=''
232
+ export DATABASE_PASSWORD=''
233
+ export USER_EMAIL=''
234
+ EOS
235
+ end
236
+ end
237
+
238
+ describe "file already exists" do
239
+ before do
240
+ %x(echo "SOME CONTENT" > #{file})
241
+ end
242
+
243
+ it "leaves .toggle.local unchanged when user responds with anything but 'y' words" do
244
+ %x(echo 'n' | ./bin/toggle --init-local #{test_dir})
245
+ File.read(file).chomp.should == 'SOME CONTENT'
246
+ end
247
+
248
+ it "replaces .toggle.local with default when user responds with 'y' words" do
249
+ %x(echo 'y' | ./bin/toggle --init-local #{test_dir})
250
+ File.read(file).chomp.should == <<-EOS.strip_heredoc
251
+ # Add any variables that you'd like below.
252
+ #
253
+ # We've included a few suggestions, but please feel free
254
+ # to modify as needed.
255
+ #
256
+ # Make sure that you source this file in your ~/.bash_profile
257
+ # or ~/.bashrc (or whereever you'd like) via:
258
+ #
259
+ # if [ -s ~/.toggle.local ] ; then source ~/.toggle.local ; fi
260
+ export DATABASE_HOST=''
261
+ export DATABASE_NAME=''
262
+ export DATABASE_USERNAME=''
263
+ export DATABASE_PASSWORD=''
264
+ export USER_EMAIL=''
265
+ EOS
266
+ end
267
+ end
268
+ end
269
+
270
+ describe "--make-defaults" do
271
+ let(:actual_key_file) { File.join(test_dir, 'key.yml') }
272
+ let(:default_key_file) { File.join(test_dir, 'key.yml.default') }
273
+ let(:actual_config_file) { File.join(test_dir, 'config.yml') }
274
+ let(:default_config_file) { File.join(test_dir, 'config.yml.default') }
275
+
276
+ before :all do
277
+ clear_toggle_files_from test_dir
278
+ end
279
+
280
+ after :each do
281
+ clear_toggle_files_from test_dir
282
+ end
283
+
284
+ describe "when user has not created any actual or .default files" do
285
+ it "creates a default key + config file in the passed path" do
286
+ %x(./bin/toggle --make-defaults #{test_dir})
287
+ File.read(default_key_file).should == <<-EOS.strip_heredoc
288
+ # Copy this file to ./key{.exts} or run the following command:
289
+ #
290
+ # $ toggle --copy-defaults [PATH]
291
+ #
292
+ # which will copy {config,key}{.exts}.default files in the given PATH to
293
+ # {config,key}{exts} (removes .default extension)
294
+ #
295
+ # You can toggle this file to use a particular config block you have
296
+ # set up. To view which top level blocks are available for a given key file,
297
+ # run:
298
+ #
299
+ # $ toggle --keys FILENAME
300
+ #
301
+ # where FILENAME is the name of a given toggle config file.
302
+ development # <= change "development" to whatever you'd like
303
+ EOS
304
+
305
+ File.read(default_config_file).should == <<-EOS.strip_heredoc
306
+ # Copy this file to ./config.yml or run the following command:
307
+ #
308
+ # $ toggle --copy-defaults [PATH]
309
+ #
310
+ # which will copy {config,key}{,.*}.default files in the given PATH to
311
+ # {config,key}{,.*} (removes .default extension)
312
+ #
313
+ # We're using the configuration conventions & setup:
314
+ # https://git.squareup.com/iacono/toggle#configuration-conventions--setup
315
+ #
316
+ # If you've set up your local variables, you should be able to copy and go!
317
+ #
318
+ # Otherwise, run:
319
+ #
320
+ # $ toggle --init-local
321
+ #
322
+ # And follow the instructions
323
+ :development:
324
+ :some: :development_setting
325
+
326
+ :production:
327
+ :some: :production_setting
328
+ # define any other config blocks that you want!
329
+ EOS
330
+ end
331
+ end
332
+
333
+ describe "when user has created an actual key file but the corresponding .default file does not exist" do
334
+ before do
335
+ %x(echo "SOME CONTENT" > #{actual_key_file})
336
+ end
337
+
338
+ it "copies the actual user created key file to the corresponding .default" do
339
+ %x(./bin/toggle --make-defaults #{test_dir})
340
+ File.read(default_key_file).should == "SOME CONTENT\n"
341
+ end
342
+ end
343
+
344
+ describe "when user has created an actual config file but the corresponding .default file does not exist" do
345
+ before do
346
+ %x(echo "SOME CONTENT" > #{actual_config_file})
347
+ end
348
+
349
+ it "copies the actual user created file to the corresponding .default" do
350
+ %x(./bin/toggle --make-defaults #{test_dir})
351
+ File.read(default_config_file).should == "SOME CONTENT\n"
352
+ end
353
+ end
354
+
355
+ describe "when user has created .default key file" do
356
+ before do
357
+ %x(echo "SOME CONTENT" > #{default_key_file})
358
+ end
359
+
360
+ it "leaves the .default file unchanged when user responds with anything but 'y' words" do
361
+ %x(echo 'n' | ./bin/toggle --make-defaults #{test_dir})
362
+ File.read(default_key_file).should == "SOME CONTENT\n"
363
+ end
364
+
365
+ it "replaces the .default file with default when user responds with 'y' words" do
366
+ %x(echo 'y' | ./bin/toggle --make-defaults #{test_dir})
367
+ File.read(default_key_file).should == <<-EOS.strip_heredoc
368
+ # Copy this file to ./key{.exts} or run the following command:
369
+ #
370
+ # $ toggle --copy-defaults [PATH]
371
+ #
372
+ # which will copy {config,key}{.exts}.default files in the given PATH to
373
+ # {config,key}{exts} (removes .default extension)
374
+ #
375
+ # You can toggle this file to use a particular config block you have
376
+ # set up. To view which top level blocks are available for a given key file,
377
+ # run:
378
+ #
379
+ # $ toggle --keys FILENAME
380
+ #
381
+ # where FILENAME is the name of a given toggle config file.
382
+ development # <= change "development" to whatever you'd like
383
+ EOS
384
+ end
385
+ end
386
+
387
+ describe "when user has created .default config file" do
388
+ before do
389
+ %x(echo "SOME CONTENT" > #{default_config_file})
390
+ end
391
+
392
+ it "leaves current config file unchanged when user responds with anything but 'y' words" do
393
+ %x(echo 'n' | ./bin/toggle --make-defaults #{test_dir})
394
+ File.read(default_config_file).should == "SOME CONTENT\n"
395
+ end
396
+
397
+ it "replaces current config file with default when user responds with 'y' words" do
398
+ %x(echo 'y' | ./bin/toggle --make-defaults #{test_dir})
399
+ File.read(default_config_file).should == <<-EOS.strip_heredoc
400
+ # Copy this file to ./config.yml or run the following command:
401
+ #
402
+ # $ toggle --copy-defaults [PATH]
403
+ #
404
+ # which will copy {config,key}{,.*}.default files in the given PATH to
405
+ # {config,key}{,.*} (removes .default extension)
406
+ #
407
+ # We're using the configuration conventions & setup:
408
+ # https://git.squareup.com/iacono/toggle#configuration-conventions--setup
409
+ #
410
+ # If you've set up your local variables, you should be able to copy and go!
411
+ #
412
+ # Otherwise, run:
413
+ #
414
+ # $ toggle --init-local
415
+ #
416
+ # And follow the instructions
417
+ :development:
418
+ :some: :development_setting
419
+
420
+ :production:
421
+ :some: :production_setting
422
+ # define any other config blocks that you want!
423
+ EOS
424
+ end
425
+ end
426
+ end
427
+ end