wdi 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +51 -11
- data/Rakefile +8 -0
- data/data/default-config.json +5 -0
- data/features/support/env.rb +2 -0
- data/features/version.feature +6 -0
- data/lib/wdi/cli.rb +11 -4
- data/lib/wdi/config.rb +212 -80
- data/lib/wdi/folder.rb +1 -1
- data/lib/wdi/version.rb +2 -2
- data/spec/config_spec.rb +315 -0
- data/spec/spec_helper.rb +14 -0
- data/wdi.gemspec +7 -4
- metadata +64 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b84a9822c9a57a90f29324b893f0eedb76f15566
|
4
|
+
data.tar.gz: 1b86197809f81e9a00e10825d179607ddcfba10d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e56f28f710f4accc04e1f385ac96188597ca03fb2126576ef580d738ce8481694c01422fef0e4d0bae8ae46e7b14499acd1ac5d6148c692d22b4cc305fc3258b
|
7
|
+
data.tar.gz: 2889d54100b1c7b3f44d160aa0e95afd79b6d2d246642fd81ab7c2df89e32937b681a69c739d1c070de1ff7291204c730369b4756274df3255217d810cf526cc
|
data/README.md
CHANGED
@@ -1,26 +1,66 @@
|
|
1
1
|
# The WDI Tool
|
2
2
|
|
3
|
-
Use this gem to set up the WDI configuration file(s) and make changes to them. These exist in the
|
3
|
+
Use this gem to set up the WDI configuration file(s) and make changes to them. These exist in the directory ~/.wdi, and are used by the breadth of WDI command line tools in order to define common constants or development/environmental settings specific to the WDI command line tools.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
```bash
|
8
|
+
gem install wdi
|
9
|
+
```
|
10
|
+
|
11
|
+
It's as easy as that!
|
12
|
+
|
13
|
+
**Warning:** the current `.bash_profile` in common use by WDI NYC has aliased `wdi` to the command `cd ~/dev/wdi`. This will override the `wdi` executable loaded in the path by the gem. The alias needs to be removed from the profile and the shell reloaded for the tool to run.
|
4
14
|
|
5
15
|
## Usage
|
6
16
|
|
17
|
+
#### Creating a WDI directory and config file
|
18
|
+
|
7
19
|
```bash
|
8
|
-
wdi init
|
9
|
-
#=> if there is no .wdi folder, it creates one
|
10
|
-
#=> by default it uses the example in data/default-config.json, or if
|
11
|
-
#=> --load is defined (as a URI), then it attempts to use that
|
12
|
-
#=> if there is a .wdi folder, this fails and suggests using `wdi config`
|
20
|
+
wdi init
|
13
21
|
```
|
14
22
|
|
23
|
+
As long as there is no `~/.wdi` directory, this command creates one. By default it uses the template file at `data/default-config.json`. If there is already a directory, you can forcefully overwrite it by using the "-f" switch. You can also specify a "load" file or URL template to copy the `config.json` file from.
|
24
|
+
|
25
|
+
#### Editing the WDI directory
|
26
|
+
|
27
|
+
```bash
|
28
|
+
# wdi add-files <files>
|
29
|
+
```
|
30
|
+
|
31
|
+
... TBD (adds a file or files to the directory, and requisite keys *files.filename* to the config)...
|
32
|
+
|
33
|
+
#### Editing a WDI config file
|
34
|
+
|
15
35
|
```bash
|
16
36
|
wdi config set <key(.key...)> <value>
|
17
37
|
wdi config get <key(.key...)>
|
18
38
|
|
19
|
-
wdi config add <key(.key...)> <value>
|
20
|
-
wdi config remove <key(.key...)> (--force)
|
39
|
+
# wdi config add <key(.key...)> <value>
|
40
|
+
# wdi config remove <key(.key...)> (--force)
|
21
41
|
|
22
42
|
wdi config keys (<key>)
|
23
43
|
|
24
|
-
# wdi get
|
25
|
-
# wdi get-
|
26
|
-
|
44
|
+
# wdi get-<key>
|
45
|
+
# wdi get-<key-parent> <rest.of.key>
|
46
|
+
# wdi add-key <key> <value>
|
47
|
+
# wdi set-<key> <value>
|
48
|
+
```
|
49
|
+
|
50
|
+
... TBD ...
|
51
|
+
|
52
|
+
#### Navigating WDI repos
|
53
|
+
|
54
|
+
```bash
|
55
|
+
# wdi go [:go.repo] [:go.pattern] <args>
|
56
|
+
```
|
57
|
+
|
58
|
+
... TBD ...
|
59
|
+
|
60
|
+
## Development
|
61
|
+
|
62
|
+
#### Testing
|
63
|
+
|
64
|
+
Use **Aruba** (Cucumber) for CLI acceptance testing, and **Rspec** for unit testing the non-CLI modules and classes. Aruba is run with the `rake test` command, and tests are in the `/features` directory, while Rspec with the `bundle exec rspec` command (test in `/specs`, as per usual).
|
65
|
+
|
66
|
+
> Note: I'm tempted to add 'active_support/core_ext/string/inflections' as a requirement... I imagine it's insanely heavy, but should be on systems already if Rails is there... But we should try to be slim if this tool is going to be required in every WDI command line tool, right?
|
data/Rakefile
CHANGED
data/data/default-config.json
CHANGED
data/lib/wdi/cli.rb
CHANGED
@@ -10,7 +10,7 @@ module WDI
|
|
10
10
|
def set(key, value)
|
11
11
|
begin
|
12
12
|
WDI::Config::set(key, value)
|
13
|
-
say "The
|
13
|
+
say "The property '#{key}' in the WDI config file has been set to '#{value}'.", :green
|
14
14
|
rescue WDI::ConfigError => e
|
15
15
|
say e.message, :red
|
16
16
|
end
|
@@ -19,7 +19,7 @@ module WDI
|
|
19
19
|
desc "get", "get a value from the WDI config file"
|
20
20
|
def get(key)
|
21
21
|
begin
|
22
|
-
say WDI::Config::get(
|
22
|
+
say WDI::Config::get(key)
|
23
23
|
rescue WDI::ConfigError => e
|
24
24
|
say e.message, :red
|
25
25
|
end
|
@@ -39,10 +39,10 @@ module WDI
|
|
39
39
|
|
40
40
|
# end
|
41
41
|
|
42
|
-
desc "keys", "list the
|
42
|
+
desc "keys", "list the properties in the WDI config file"
|
43
43
|
def keys(key=nil)
|
44
44
|
begin
|
45
|
-
say WDI::Config::
|
45
|
+
say WDI::Config::properties(key).join("\n")
|
46
46
|
rescue WDI::ConfigError => e
|
47
47
|
say e.message, :red
|
48
48
|
end
|
@@ -50,6 +50,13 @@ module WDI
|
|
50
50
|
end
|
51
51
|
|
52
52
|
class Wdi < Thor
|
53
|
+
#class_option :version, alias: "-v", type: :boolean
|
54
|
+
|
55
|
+
desc "version", "get current WDI tool version"
|
56
|
+
def version
|
57
|
+
say WDI::VERSION
|
58
|
+
end
|
59
|
+
|
53
60
|
desc "init", "initialize a new WDI directory at ~/.wdi"
|
54
61
|
method_option :load,
|
55
62
|
aliases: ["-l"],
|
data/lib/wdi/config.rb
CHANGED
@@ -6,7 +6,197 @@ require "pry"
|
|
6
6
|
|
7
7
|
module WDI
|
8
8
|
module Config
|
9
|
-
KEY_REGEX
|
9
|
+
KEY_REGEX = /^[a-z.]*$/ # only lowercase words separated by periods
|
10
|
+
VALUE_AS_KEY_REGEX = /:[a-z._]+/ # a value containing at least one word prefixed by ':'
|
11
|
+
ALLOWED_BASH_REGEX = /(`(echo|pwd|ls|whoami)[^\|;&]*`)/
|
12
|
+
|
13
|
+
##############################################################
|
14
|
+
class ConfigFile
|
15
|
+
attr_reader :pairs
|
16
|
+
|
17
|
+
def initialize(json_configuration)
|
18
|
+
config = JSON.parse(json_configuration, symbolize_names: true)
|
19
|
+
|
20
|
+
@pairs = {}
|
21
|
+
recursive_build_pairs_from config
|
22
|
+
ensure_format_of_pairs
|
23
|
+
end
|
24
|
+
|
25
|
+
def has_key?(key)
|
26
|
+
key = translate_incoming(key)
|
27
|
+
@pairs.key?(key)
|
28
|
+
end
|
29
|
+
|
30
|
+
def value_at(key)
|
31
|
+
key = translate_incoming(key)
|
32
|
+
|
33
|
+
if @pairs.key?(key)
|
34
|
+
if @pairs[key].is_a? Array
|
35
|
+
return @pairs[key].map {|value| retrieve_value_with_references(value) }
|
36
|
+
else
|
37
|
+
return retrieve_value_with_references(@pairs[key])
|
38
|
+
end
|
39
|
+
elsif keys_with_prefix(key)
|
40
|
+
raise WDI::ConfigError,
|
41
|
+
"This key doesn't represent a property in the WDI config file. " +
|
42
|
+
"Try `wdi config keys #{key}`."
|
43
|
+
else
|
44
|
+
return false
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def keys_with_value(value)
|
49
|
+
key_list = @pairs.select {|k,v| v == value}.keys
|
50
|
+
key_list.count == 0 ? false : key_list.map{|k| translate_outgoing(k)}
|
51
|
+
end
|
52
|
+
|
53
|
+
def set_key_value(key, value)
|
54
|
+
key = translate_incoming(key)
|
55
|
+
|
56
|
+
raise WDI::ConfigError,
|
57
|
+
"This key is not in the WDI config file." unless @pairs.key?(key)
|
58
|
+
raise WDI::ConfigError,
|
59
|
+
"This value is not formatted correctly for the WDI config file." unless value.is_a?(String)
|
60
|
+
disallow_bad_references_in value
|
61
|
+
@pairs[key] = value
|
62
|
+
end
|
63
|
+
|
64
|
+
def add_key_value(key, value)
|
65
|
+
key = translate_incoming(key)
|
66
|
+
disallow_bad_references_in value
|
67
|
+
|
68
|
+
if has_key?(key)
|
69
|
+
if @pairs[key].is_a? Array
|
70
|
+
@pairs[key] << value
|
71
|
+
else
|
72
|
+
@pairs[key] = [@pairs[key],value]
|
73
|
+
end
|
74
|
+
else
|
75
|
+
@pairs[key] = value
|
76
|
+
end
|
77
|
+
return @pairs[key]
|
78
|
+
end
|
79
|
+
|
80
|
+
def keys
|
81
|
+
@pairs.keys.map{|k| translate_outgoing(k)}
|
82
|
+
end
|
83
|
+
|
84
|
+
def keys_with_prefix(prefix=nil)
|
85
|
+
return keys if prefix.nil?
|
86
|
+
prefix = translate_outgoing(translate_incoming(prefix)) # force correct string format
|
87
|
+
key_list = keys.select{|k| (k =~ Regexp.new(prefix)) == 0 }
|
88
|
+
key_list.count == 0 ? false : key_list
|
89
|
+
end
|
90
|
+
|
91
|
+
def to_h
|
92
|
+
result = {}
|
93
|
+
|
94
|
+
keys.each do |key|
|
95
|
+
add_child_node(result, key, @pairs[translate_incoming(key)])
|
96
|
+
end
|
97
|
+
|
98
|
+
return result
|
99
|
+
end
|
100
|
+
|
101
|
+
def to_json
|
102
|
+
JSON.pretty_generate(self.to_h)
|
103
|
+
end
|
104
|
+
|
105
|
+
def to_s
|
106
|
+
@pairs.to_s
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
def translate_incoming(key)
|
111
|
+
if key.is_a? String
|
112
|
+
key.gsub(/\./, "_").to_sym
|
113
|
+
elsif key.is_a? Symbol
|
114
|
+
key
|
115
|
+
else
|
116
|
+
raise WDI::ConfigError,
|
117
|
+
"This property is not formatted correctly for the WDI config file."
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def interpolate_commands_in(value)
|
122
|
+
value.gsub(ALLOWED_BASH_REGEX) do |command|
|
123
|
+
eval(command).chomp
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def translate_outgoing(key)
|
128
|
+
key.to_s.gsub(/_/,".")
|
129
|
+
end
|
130
|
+
|
131
|
+
def retrieve_value_with_references(value)
|
132
|
+
value = interpolate_commands_in value
|
133
|
+
check_value = disallow_bad_references_in value
|
134
|
+
|
135
|
+
return value if (check_value =~ VALUE_AS_KEY_REGEX).nil?
|
136
|
+
check_value.gsub(VALUE_AS_KEY_REGEX) {|reference| value_at(reference[1..-1])}
|
137
|
+
end
|
138
|
+
|
139
|
+
def ensure_format_of_pairs
|
140
|
+
pairs.each_pair do |key, value|
|
141
|
+
key = translate_outgoing(key)
|
142
|
+
|
143
|
+
if (key =~ KEY_REGEX).nil? || key[0] == "." || key[-1] == "."
|
144
|
+
raise WDI::ConfigError,
|
145
|
+
"This property is not formatted correctly for the WDI config file."
|
146
|
+
end
|
147
|
+
|
148
|
+
if !(value.is_a?(String) || value.is_a?(Array))
|
149
|
+
raise WDI::ConfigError,
|
150
|
+
"This value is not formatted correctly for the WDI config file " + \
|
151
|
+
"(must be a string or an array of strings)."
|
152
|
+
else
|
153
|
+
disallow_bad_references_in value
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def disallow_bad_references_in(value)
|
159
|
+
check_value = value.gsub(VALUE_AS_KEY_REGEX) do |reference|
|
160
|
+
translate_outgoing(reference) # only translate to dots if matches reference
|
161
|
+
end
|
162
|
+
|
163
|
+
check_value.scan(VALUE_AS_KEY_REGEX) do |reference|
|
164
|
+
unless has_key?(reference[1..-1])
|
165
|
+
raise WDI::ConfigError,
|
166
|
+
"This value is not formatted correctly for the WDI config file " + \
|
167
|
+
"(malformed reference)."
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def recursive_build_pairs_from(tree, parent_key="")
|
173
|
+
tree.each_pair do |child_key, value|
|
174
|
+
if value.is_a?(Hash)
|
175
|
+
recursive_build_pairs_from(value, append_keys(parent_key, child_key))
|
176
|
+
else
|
177
|
+
@pairs[append_keys(parent_key, child_key).to_sym] = value
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def add_child_node(node, key, value)
|
183
|
+
parent, child = key.split(".", 2)
|
184
|
+
|
185
|
+
if child.nil?
|
186
|
+
node[parent.to_sym] = value
|
187
|
+
else
|
188
|
+
node[parent.to_sym] = {} if node[parent.to_sym].nil?
|
189
|
+
add_child_node(node[parent.to_sym], child, value)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def append_keys(parent, child)
|
194
|
+
parent = (parent.nil? || parent == "") ? "" : parent.to_s + "_"
|
195
|
+
child = (child.nil? || child == "") ? "" : child.to_s
|
196
|
+
parent + child
|
197
|
+
end
|
198
|
+
end
|
199
|
+
###############################################################
|
10
200
|
|
11
201
|
def self.path
|
12
202
|
File.expand_path("config.json", WDI::Folder::path)
|
@@ -16,25 +206,19 @@ module WDI
|
|
16
206
|
File.exists?(self.path)
|
17
207
|
end
|
18
208
|
|
19
|
-
def self.
|
20
|
-
@@config ||= self.
|
209
|
+
def self.config
|
210
|
+
@@config ||= self.load_local_configuration
|
21
211
|
end
|
22
212
|
|
23
|
-
def self.
|
24
|
-
@@config =
|
213
|
+
def self.load_local_configuration
|
214
|
+
@@config = WDI::Config::ConfigFile.new(IO.read(self.path))
|
25
215
|
end
|
26
216
|
|
27
|
-
def self.
|
28
|
-
File.open(File.expand_path("config.json", WDI::Folder::path), "w+") do |f|
|
29
|
-
f.write JSON.pretty_generate(self.file)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def self.load_file(config_uri)
|
217
|
+
def self.load_configuration_from(config_uri)
|
34
218
|
begin
|
35
219
|
uri = URI(config_uri)
|
36
220
|
config_file = ["http", "https"].include?(uri.scheme) ? uri.open.read : IO.read(config_uri)
|
37
|
-
@@config =
|
221
|
+
@@config = WDI::Config::ConfigFile.new config_file
|
38
222
|
self.save
|
39
223
|
|
40
224
|
rescue Errno::ENOENT => e
|
@@ -48,84 +232,32 @@ module WDI
|
|
48
232
|
end
|
49
233
|
end
|
50
234
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
raise WDI::ConfigError, "This key is not in the WDI config file." if key.nil?
|
55
|
-
raise WDI::ConfigError,
|
56
|
-
"This key doesn't represent a property in the WDI config file. " +
|
57
|
-
"Try `wdi config keys #{key_name}`." if key.is_a?(Hash)
|
58
|
-
return key
|
59
|
-
end
|
60
|
-
|
61
|
-
def self.set(key_name, new_value)
|
62
|
-
current_value = WDI::Config::translate(key_name)
|
63
|
-
raise WDI::ConfigError,
|
64
|
-
"This key doesn't represent a property in the WDI config file. " +
|
65
|
-
"Try `wdi config keys #{key_name}`." if current_value.is_a?(Hash)
|
66
|
-
|
67
|
-
|
68
|
-
self.set_child(self.file, key_name, new_value)
|
69
|
-
self.save
|
70
|
-
end
|
71
|
-
|
72
|
-
def self.set_child(key, key_name, value)
|
73
|
-
parent, child = key_name.split(".", 2)
|
74
|
-
if child.nil?
|
75
|
-
key[parent.to_sym] = value
|
76
|
-
else
|
77
|
-
self.set_child(key[parent.to_sym], child, value)
|
235
|
+
def self.save
|
236
|
+
File.open(File.expand_path("config.json", WDI::Folder::path), "w+") do |f|
|
237
|
+
f.write self.config.to_json
|
78
238
|
end
|
79
239
|
end
|
80
240
|
|
81
|
-
|
82
|
-
|
83
|
-
"There are no (sub-)keys in the WDI config file that fit this criteria." unless tree.is_a?(Hash)
|
84
|
-
|
85
|
-
tree.each_pair do |child_key, value|
|
86
|
-
if value.is_a?(Hash)
|
87
|
-
self.keys(value, self.append_keys(parent_key, child_key), key_list)
|
88
|
-
else
|
89
|
-
key_list << self.append_keys(parent_key, child_key)
|
90
|
-
end
|
91
|
-
end
|
241
|
+
###############################################################
|
242
|
+
## WRAPPER MODULE METHODS
|
92
243
|
|
93
|
-
|
244
|
+
def self.create(config_uri)
|
245
|
+
config_uri.nil? ? self.load_local_configuration : self.load_configuration_from(config_uri)
|
94
246
|
end
|
95
247
|
|
96
|
-
|
97
|
-
|
98
|
-
def self.append_keys(parent, child)
|
99
|
-
parent = (parent.nil? || parent == "") ? "" : parent.to_s + "."
|
100
|
-
child = (child.nil? || child == "") ? "" : child.to_s
|
101
|
-
parent + child
|
248
|
+
def self.get(property)
|
249
|
+
self.config.value_at property
|
102
250
|
end
|
103
251
|
|
104
|
-
def self.
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
raise WDI::ConfigError,
|
109
|
-
"This key is not formatted correctly for the WDI config file." unless key =~ KEY_REGEX
|
110
|
-
parent, child = key.split(".", 2)
|
111
|
-
value = tree[parent.to_sym]
|
112
|
-
raise WDI::ConfigError, "This key is not in the WDI config file." if value.nil?
|
252
|
+
def self.set(property, value)
|
253
|
+
self.config.set_key_value property, value
|
254
|
+
self.save
|
255
|
+
end
|
113
256
|
|
114
|
-
|
257
|
+
def self.properties(prefix=nil)
|
258
|
+
self.config.keys_with_prefix prefix
|
115
259
|
end
|
116
260
|
|
117
|
-
def self.safe_replace(config)
|
118
|
-
JSON.recurse_proc(config) do |line|
|
119
|
-
if line.is_a?(String)
|
120
|
-
# so this is not REALLY safe, but should be safe enough... maybe even too restrictive
|
121
|
-
allowed_bash_regex = /(`(echo|pwd|ls)[^\|;&]*`)/
|
122
|
-
|
123
|
-
result = eval( line[allowed_bash_regex] )
|
124
|
-
line.gsub!( allowed_bash_regex, result.chomp ) unless result.nil?
|
125
|
-
end
|
126
|
-
end
|
127
261
|
|
128
|
-
return config
|
129
|
-
end
|
130
262
|
end
|
131
263
|
end
|
data/lib/wdi/folder.rb
CHANGED
data/lib/wdi/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
module
|
2
|
-
VERSION = "0.0.
|
1
|
+
module WDI
|
2
|
+
VERSION = "0.0.3"
|
3
3
|
end
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,315 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe WDI::Config do
|
4
|
+
describe WDI::Config::ConfigFile do # namespacing weirdness...
|
5
|
+
config_json_contents_with_interpolation = <<-JSON_CONTENTS
|
6
|
+
{
|
7
|
+
"name": "`whoami`",
|
8
|
+
"base": "`echo $HOME`/dev/wdi",
|
9
|
+
"repos": {
|
10
|
+
"classes": {
|
11
|
+
"current": "`echo $HOME`/dev/wdi/class_name"
|
12
|
+
}
|
13
|
+
},
|
14
|
+
"go": {
|
15
|
+
"repo": ":repos.classes.current",
|
16
|
+
"pattern": "/$1/$2/:name"
|
17
|
+
}
|
18
|
+
}
|
19
|
+
JSON_CONTENTS
|
20
|
+
|
21
|
+
config_json_contents = <<-JSON_CONTENTS
|
22
|
+
{
|
23
|
+
"name": "philip",
|
24
|
+
"base": "/Users/philip/dev/wdi",
|
25
|
+
"repos": {
|
26
|
+
"classes": {
|
27
|
+
"current": "/Users/philip/dev/wdi/class_name"
|
28
|
+
}
|
29
|
+
},
|
30
|
+
"go": {
|
31
|
+
"repo": ":repos.classes.current",
|
32
|
+
"pattern": "/$1/$2/:name"
|
33
|
+
}
|
34
|
+
}
|
35
|
+
JSON_CONTENTS
|
36
|
+
|
37
|
+
describe "#initialize" do
|
38
|
+
it "raises an error if properties aren't formatted for the config to work" do
|
39
|
+
expect {WDI::Config::ConfigFile.new('{"name1":"pj"}')}.to raise_error
|
40
|
+
expect {WDI::Config::ConfigFile.new('{"name_":"pj"}')}.to raise_error
|
41
|
+
expect {WDI::Config::ConfigFile.new('{"name.":"pj"}')}.to raise_error
|
42
|
+
expect {WDI::Config::ConfigFile.new('{".name":"pj"}')}.to raise_error
|
43
|
+
end
|
44
|
+
|
45
|
+
it "allows bash commands in the values" do
|
46
|
+
keys_values = {
|
47
|
+
name: "`whoami`",
|
48
|
+
base: "`echo $HOME`/dev/wdi",
|
49
|
+
repos_classes_current: "`echo $HOME`/dev/wdi/class_name",
|
50
|
+
go_repo: ":repos.classes.current",
|
51
|
+
go_pattern: "/$1/$2/:name"
|
52
|
+
}
|
53
|
+
expect(WDI::Config::ConfigFile.new(config_json_contents_with_interpolation).pairs).to \
|
54
|
+
eql(keys_values)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "does not allow string values to have colon-prefixed words unless they reference properties" do
|
58
|
+
expect {WDI::Config::ConfigFile.new('{"name":":not_name"}')}.to raise_error
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
let!(:config) {WDI::Config::ConfigFile.new(config_json_contents)}
|
63
|
+
|
64
|
+
describe "#value_at" do
|
65
|
+
it "returns the value at the given key (as a symbol)" do
|
66
|
+
expect(config.value_at(:name)).to eql("philip")
|
67
|
+
end
|
68
|
+
|
69
|
+
it "returns the value at the given key (as a string)" do
|
70
|
+
expect(config.value_at("name")).to eql("philip")
|
71
|
+
end
|
72
|
+
|
73
|
+
it "works with dotted key strings appropriately" do
|
74
|
+
expect(config.value_at("repos.classes.current")).to \
|
75
|
+
eql("/Users/philip/dev/wdi/class_name")
|
76
|
+
end
|
77
|
+
|
78
|
+
it "works with underscored key symbols appropriately" do
|
79
|
+
expect(config.value_at(:repos_classes_current)).to \
|
80
|
+
eql("/Users/philip/dev/wdi/class_name")
|
81
|
+
end
|
82
|
+
|
83
|
+
it "raises an error when the key exists but is not a leaf node" do
|
84
|
+
expect {config.value_at("repos.classes")}.to raise_error
|
85
|
+
expect {config.value_at(:repos_classes)}.to raise_error
|
86
|
+
end
|
87
|
+
|
88
|
+
it "returns false when the key is not in the config file" do
|
89
|
+
expect(config.value_at(:not_a_key)).to be_false
|
90
|
+
end
|
91
|
+
|
92
|
+
context "the value is a property reference, ie starts with a colon" do
|
93
|
+
it "returns the referenced property value" do
|
94
|
+
expect(config.value_at("go.repo")).to \
|
95
|
+
eql("/Users/philip/dev/wdi/class_name")
|
96
|
+
end
|
97
|
+
|
98
|
+
it "works with either format for the reference" do
|
99
|
+
config.set_key_value "go.repo", ":repos_classes_current"
|
100
|
+
expect(config.value_at("go.repo")).to \
|
101
|
+
eql("/Users/philip/dev/wdi/class_name")
|
102
|
+
end
|
103
|
+
|
104
|
+
it "interpolates if the reference is in the value" do
|
105
|
+
expect(config.value_at("go.pattern")).to eql("/$1/$2/philip")
|
106
|
+
end
|
107
|
+
|
108
|
+
it "raises an error when the referenced property does not exist", :broken => true do
|
109
|
+
allow(config).to receive(:disallow_bad_references_in) # not totally secure in this working...
|
110
|
+
config.set_key_value "go.repo", ":not_a_value"
|
111
|
+
|
112
|
+
expect {config.value_at("go.repo")}.to raise_error
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context "the value contains an allowed bash command" do
|
117
|
+
let!(:config) {WDI::Config::ConfigFile.new(config_json_contents_with_interpolation)}
|
118
|
+
|
119
|
+
it "returns the value with the command result interpolated" do
|
120
|
+
expect(config.value_at("base")).to eql((`echo $HOME`).chomp + "/dev/wdi")
|
121
|
+
end
|
122
|
+
|
123
|
+
it "works even when it was referenced" do
|
124
|
+
expect(config.value_at("go.repo")).to eql((`echo $HOME`).chomp + "/dev/wdi/class_name")
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe "#set_key_value" do
|
130
|
+
it "updates the value at the given key" do
|
131
|
+
config.set_key_value "name", "pj"
|
132
|
+
expect(config.value_at("name")).to eql("pj")
|
133
|
+
end
|
134
|
+
|
135
|
+
it "works when key is given in symbol format" do
|
136
|
+
config.set_key_value :repos_classes_current, "/"
|
137
|
+
expect(config.value_at("repos.classes.current")).to eql("/")
|
138
|
+
end
|
139
|
+
|
140
|
+
it "raises an error if the key doesn't exist" do
|
141
|
+
expect {config.set_key_value "nom", "pj"}.to raise_error
|
142
|
+
end
|
143
|
+
|
144
|
+
it "raises an error if the value isn't a string" do
|
145
|
+
expect {config.set_key_value "name", :pj}.to raise_error
|
146
|
+
end
|
147
|
+
|
148
|
+
context "with string values that have colon-prefixed words" do
|
149
|
+
it "does not allow them unless they reference properties" do
|
150
|
+
expect {config.set_key_value "name", "hello i am :not_name"}.to raise_error
|
151
|
+
end
|
152
|
+
|
153
|
+
it "allows them when they reference properties" do
|
154
|
+
expect {config.set_key_value "name", "hello i am :name"}.not_to raise_error
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe "#has_key?" do
|
160
|
+
it "returns true if the key exists" do
|
161
|
+
expect(config.has_key?("name")).to be_true
|
162
|
+
end
|
163
|
+
|
164
|
+
it "works when key is given in symbol format" do
|
165
|
+
expect(config.has_key?(:repos_classes_current)).to be_true
|
166
|
+
end
|
167
|
+
|
168
|
+
it "returns false if the key doesn't exist" do
|
169
|
+
expect(config.has_key?("nom")).to be_false
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe "#keys_with_value" do
|
174
|
+
it "returns the keys at the given value (as a symbol)" do
|
175
|
+
expect(config.keys_with_value("philip")).to eql(["name"])
|
176
|
+
end
|
177
|
+
|
178
|
+
it "returns the keys with dots replaced by underscores" do
|
179
|
+
expect(config.keys_with_value("/Users/philip/dev/wdi/class_name")).to \
|
180
|
+
eql(["repos.classes.current"])
|
181
|
+
end
|
182
|
+
|
183
|
+
it "returns multiple keys if necessary" do
|
184
|
+
config.add_key_value("repos.instructors.current", "/Users/philip/dev/wdi/class_name")
|
185
|
+
expect(config.keys_with_value("/Users/philip/dev/wdi/class_name")).to \
|
186
|
+
eql(["repos.classes.current","repos.instructors.current"])
|
187
|
+
end
|
188
|
+
|
189
|
+
it "returns false if the value is not present" do
|
190
|
+
expect(config.keys_with_value("not_a_value")).to be_false
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
describe "#keys_with_prefix" do
|
195
|
+
it "returns the keys with the given prefix" do
|
196
|
+
expect(config.keys_with_prefix("go")).to eql(["go.repo","go.pattern"])
|
197
|
+
end
|
198
|
+
|
199
|
+
it "returns the key itself if the prefix is a key" do
|
200
|
+
expect(config.keys_with_prefix("go.repo")).to eql(["go.repo"])
|
201
|
+
end
|
202
|
+
|
203
|
+
it "returns false when the key is not present" do
|
204
|
+
expect(config.keys_with_prefix("not_a_key")).to be_false
|
205
|
+
end
|
206
|
+
|
207
|
+
it "returns all keys when given no prefix" do
|
208
|
+
keys = ["name","base","repos.classes.current","go.repo","go.pattern"]
|
209
|
+
expect(config.keys_with_prefix).to match_array(keys)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
describe "#add_key_value" do
|
214
|
+
it "adds a new key with the given value" do
|
215
|
+
config.add_key_value("repos.instructors.current", "/Users/philip/dev/wdi/class_name")
|
216
|
+
expect(config.value_at("repos.instructors.current")).to eql("/Users/philip/dev/wdi/class_name")
|
217
|
+
end
|
218
|
+
|
219
|
+
context "when the given key already exists and is not an array" do
|
220
|
+
it "turns the property into an array and pushes the new value on to it" do
|
221
|
+
config.add_key_value("name", "pj")
|
222
|
+
expect(config.value_at("name")).to match_array(["philip","pj"])
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
context "when the given key already exists and is an array" do
|
227
|
+
it "pushes the new value on to it" do
|
228
|
+
config.add_key_value("name", "pj")
|
229
|
+
config.add_key_value("name", "felipe")
|
230
|
+
expect(config.value_at("name")).to match_array(["philip","pj","felipe"])
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
context "with string values that have colon-prefixed words" do
|
235
|
+
it "does not allow them unless they reference properties" do
|
236
|
+
expect {config.add_key_value("name", "hello i am :not_name")}.to raise_error
|
237
|
+
end
|
238
|
+
|
239
|
+
it "allows them when they reference properties" do
|
240
|
+
expect {config.add_key_value("name", "hello i am :name")}.not_to raise_error
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
describe "#pairs", :unnecessary => true do
|
246
|
+
it "returns all of the key-value pairs" do
|
247
|
+
keys_values = {
|
248
|
+
name: "philip",
|
249
|
+
base: "/Users/philip/dev/wdi",
|
250
|
+
repos_classes_current: "/Users/philip/dev/wdi/class_name",
|
251
|
+
go_repo: ":repos.classes.current",
|
252
|
+
go_pattern: "/$1/$2/:name"
|
253
|
+
}
|
254
|
+
expect(config.pairs).to eql(keys_values)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
describe "#keys", :unnecessary => true do
|
259
|
+
it "returns all of the keys" do
|
260
|
+
keys = ["name","base","repos.classes.current","go.repo","go.pattern"]
|
261
|
+
expect(config.keys).to match_array(keys)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
describe "#to_h" do
|
266
|
+
it "returns the config's pairs as a hash-tree" do
|
267
|
+
config = WDI::Config::ConfigFile.new(config_json_contents_with_interpolation)
|
268
|
+
hash_tree = {
|
269
|
+
name: "`whoami`",
|
270
|
+
base: "`echo $HOME`/dev/wdi",
|
271
|
+
repos: {
|
272
|
+
classes: {
|
273
|
+
current: "`echo $HOME`/dev/wdi/class_name"
|
274
|
+
}
|
275
|
+
},
|
276
|
+
go: {
|
277
|
+
repo: ":repos.classes.current",
|
278
|
+
pattern: "/$1/$2/:name"
|
279
|
+
}
|
280
|
+
}
|
281
|
+
|
282
|
+
expect(config.to_h).to eql(hash_tree)
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
describe "#to_json" do
|
287
|
+
it "returns the config's pairs as a JSON string representing the hash-tree" do
|
288
|
+
config = WDI::Config::ConfigFile.new(config_json_contents_with_interpolation)
|
289
|
+
hash_tree = {
|
290
|
+
name: "`whoami`",
|
291
|
+
base: "`echo $HOME`/dev/wdi",
|
292
|
+
repos: {
|
293
|
+
classes: {
|
294
|
+
current: "`echo $HOME`/dev/wdi/class_name"
|
295
|
+
}
|
296
|
+
},
|
297
|
+
go: {
|
298
|
+
repo: ":repos.classes.current",
|
299
|
+
pattern: "/$1/$2/:name"
|
300
|
+
}
|
301
|
+
}
|
302
|
+
|
303
|
+
expect(config.to_json).to eql(JSON.pretty_generate(hash_tree)) #
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
describe "#to_s" do
|
308
|
+
it "returns a string version of the contents (not the correct json, but key-val pairs)" do
|
309
|
+
expect(config.to_s).to eql(config.pairs.to_s)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
end
|
314
|
+
|
315
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require "bundler"
|
2
|
+
require "pry"
|
3
|
+
|
4
|
+
Bundler.setup
|
5
|
+
|
6
|
+
Dir[File.expand_path('../../lib/wdi/*.rb', __FILE__)].each {|file| require file }
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
config.filter_run_excluding unnecessary: true
|
10
|
+
config.filter_run_excluding broken: true
|
11
|
+
|
12
|
+
config.color = true
|
13
|
+
config.formatter = "documentation"
|
14
|
+
end
|
data/wdi.gemspec
CHANGED
@@ -5,10 +5,11 @@ require 'wdi/version'
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "wdi"
|
8
|
-
spec.version =
|
8
|
+
spec.version = WDI::VERSION
|
9
9
|
spec.authors = ["Philip Hughes"]
|
10
10
|
spec.email = ["pj@ga.co"]
|
11
|
-
spec.summary = %q{A utility for
|
11
|
+
spec.summary = %q{A utility for working with (and configuring) the WDI directory and WDI command line tools.}
|
12
|
+
spec.description = %q{TBC}
|
12
13
|
spec.homepage = "https://github.com/ga-instructors/wdi-gem"
|
13
14
|
spec.license = "BSD 3-Clause"
|
14
15
|
|
@@ -18,8 +19,10 @@ Gem::Specification.new do |spec|
|
|
18
19
|
spec.require_paths = ["lib"]
|
19
20
|
|
20
21
|
spec.add_development_dependency "bundler", "~> 1.5"
|
21
|
-
spec.add_development_dependency "rake",
|
22
|
-
spec.add_development_dependency "
|
22
|
+
spec.add_development_dependency "rake", "~> 10.2"
|
23
|
+
spec.add_development_dependency "rspec", '~> 2.14', '>= 2.14.1'
|
24
|
+
spec.add_development_dependency "aruba", '~> 0.5', '>= 0.5.4'
|
25
|
+
spec.add_development_dependency "pry", '~> 0.9', '>= 0.9.12'
|
23
26
|
|
24
27
|
spec.add_runtime_dependency "thor", "~> 0.19"
|
25
28
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wdi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Philip Hughes
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-03-
|
11
|
+
date: 2014-03-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -28,30 +28,76 @@ dependencies:
|
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.2'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.2'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.14'
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: 2.14.1
|
51
|
+
type: :development
|
52
|
+
prerelease: false
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - "~>"
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '2.14'
|
31
58
|
- - ">="
|
32
59
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
60
|
+
version: 2.14.1
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: aruba
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0.5'
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 0.5.4
|
34
71
|
type: :development
|
35
72
|
prerelease: false
|
36
73
|
version_requirements: !ruby/object:Gem::Requirement
|
37
74
|
requirements:
|
75
|
+
- - "~>"
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0.5'
|
38
78
|
- - ">="
|
39
79
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
80
|
+
version: 0.5.4
|
41
81
|
- !ruby/object:Gem::Dependency
|
42
82
|
name: pry
|
43
83
|
requirement: !ruby/object:Gem::Requirement
|
44
84
|
requirements:
|
85
|
+
- - "~>"
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0.9'
|
45
88
|
- - ">="
|
46
89
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
90
|
+
version: 0.9.12
|
48
91
|
type: :development
|
49
92
|
prerelease: false
|
50
93
|
version_requirements: !ruby/object:Gem::Requirement
|
51
94
|
requirements:
|
95
|
+
- - "~>"
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0.9'
|
52
98
|
- - ">="
|
53
99
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
100
|
+
version: 0.9.12
|
55
101
|
- !ruby/object:Gem::Dependency
|
56
102
|
name: thor
|
57
103
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,7 +112,7 @@ dependencies:
|
|
66
112
|
- - "~>"
|
67
113
|
- !ruby/object:Gem::Version
|
68
114
|
version: '0.19'
|
69
|
-
description:
|
115
|
+
description: TBC
|
70
116
|
email:
|
71
117
|
- pj@ga.co
|
72
118
|
executables:
|
@@ -81,11 +127,15 @@ files:
|
|
81
127
|
- Rakefile
|
82
128
|
- bin/wdi
|
83
129
|
- data/default-config.json
|
130
|
+
- features/support/env.rb
|
131
|
+
- features/version.feature
|
84
132
|
- lib/wdi.rb
|
85
133
|
- lib/wdi/cli.rb
|
86
134
|
- lib/wdi/config.rb
|
87
135
|
- lib/wdi/folder.rb
|
88
136
|
- lib/wdi/version.rb
|
137
|
+
- spec/config_spec.rb
|
138
|
+
- spec/spec_helper.rb
|
89
139
|
- wdi.gemspec
|
90
140
|
homepage: https://github.com/ga-instructors/wdi-gem
|
91
141
|
licenses:
|
@@ -110,6 +160,10 @@ rubyforge_project:
|
|
110
160
|
rubygems_version: 2.2.2
|
111
161
|
signing_key:
|
112
162
|
specification_version: 4
|
113
|
-
summary: A utility for
|
114
|
-
tools.
|
115
|
-
test_files:
|
163
|
+
summary: A utility for working with (and configuring) the WDI directory and WDI command
|
164
|
+
line tools.
|
165
|
+
test_files:
|
166
|
+
- features/support/env.rb
|
167
|
+
- features/version.feature
|
168
|
+
- spec/config_spec.rb
|
169
|
+
- spec/spec_helper.rb
|