knife-table 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +6 -0
- data/README.md +19 -8
- data/knife-table.gemspec +6 -2
- data/lib/chef/knife/table_clear.rb +1 -1
- data/lib/chef/knife/table_order.rb +154 -0
- data/lib/chef/knife/table_serve.rb +15 -20
- data/lib/chef/knife/table_set.rb +41 -9
- data/lib/knife-table/helpers.rb +10 -0
- data/lib/knife-table/version.rb +3 -1
- metadata +29 -7
- data/lib/chef/knife/data_holder.rb +0 -54
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,18 +1,20 @@
|
|
1
|
-
#
|
1
|
+
# KnifeTable
|
2
2
|
|
3
|
-
|
3
|
+
KnifeTable is a knife plugin to aid in cookbook development
|
4
4
|
workflow. Its intention is to help automate versioning
|
5
5
|
within environments and cookbook freezing based on a stable
|
6
|
-
branch. Building off of the knife-spork plugin
|
6
|
+
branch. Building off of the knife-spork plugin KnifeTable
|
7
7
|
helps to provide consistency within the environment.
|
8
8
|
|
9
9
|
|
10
10
|
## Usage
|
11
11
|
|
12
|
-
Currently,
|
12
|
+
Currently, the supported workflow is as follows:
|
13
13
|
|
14
14
|
`knife table set`
|
15
15
|
|
16
|
+
`knife table order`
|
17
|
+
|
16
18
|
and
|
17
19
|
|
18
20
|
`knife table serve`
|
@@ -25,13 +27,22 @@ of what is being added:
|
|
25
27
|
|
26
28
|
`knife table set new feature`
|
27
29
|
|
28
|
-
This will create a new working branch named '
|
29
|
-
|
30
|
-
|
31
|
-
setting:
|
30
|
+
This will create a new working branch named 'new_feature'. A default prefix
|
31
|
+
can be added the branch name via the `-p` option. If it is known what cookbooks
|
32
|
+
will be modified, you can provide them while setting:
|
32
33
|
|
33
34
|
`knife table set -c iptables,mysql new feature`
|
34
35
|
|
36
|
+
### Order
|
37
|
+
|
38
|
+
Once the code has been updated, tested and is ready for review, the order
|
39
|
+
can be placed which will create a new pull request:
|
40
|
+
|
41
|
+
`knife table order`
|
42
|
+
|
43
|
+
The order option will also optionally run foodcritic and require a passing
|
44
|
+
result before proceeding with the pull request generation.
|
45
|
+
|
35
46
|
### Service
|
36
47
|
|
37
48
|
Service works on the assumption that any new code into the stable branch (master
|
data/knife-table.gemspec
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__)) + '/lib/'
|
2
|
+
require 'knife-table/version'
|
1
3
|
Gem::Specification.new do |s|
|
2
4
|
s.name = 'knife-table'
|
3
|
-
s.version =
|
5
|
+
s.version = KnifeTable::VERSION.version
|
4
6
|
s.summary = 'Help chef set and serve the table'
|
5
7
|
s.author = 'Chris Roberts'
|
6
8
|
s.email = 'chrisroberts.code@gmail.com'
|
@@ -8,5 +10,7 @@ Gem::Specification.new do |s|
|
|
8
10
|
s.description = "Chef's table"
|
9
11
|
s.require_path = 'lib'
|
10
12
|
s.files = Dir.glob('**/*')
|
11
|
-
s.add_dependency 'knife-spork'
|
13
|
+
s.add_dependency 'knife-spork', '>= 0.1.11'
|
14
|
+
s.add_dependency 'hub', '>= 1.10.1'
|
15
|
+
s.add_dependency 'foodcritic', '>= 1.4.0'
|
12
16
|
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
require 'open3'
|
2
|
+
require 'knife-table/helpers'
|
3
|
+
|
4
|
+
module KnifeTable
|
5
|
+
class TableOrder < Chef::Knife
|
6
|
+
|
7
|
+
include KnifeTable::Helpers
|
8
|
+
|
9
|
+
deps do
|
10
|
+
require 'git'
|
11
|
+
require 'hub'
|
12
|
+
end
|
13
|
+
|
14
|
+
banner 'knife table order [BRANCH]'
|
15
|
+
|
16
|
+
option :upstream_user,
|
17
|
+
:short => '-u USER',
|
18
|
+
:long => '--upstream-user USER',
|
19
|
+
:description => 'Username for upstream github account'
|
20
|
+
|
21
|
+
option :upstream_branch,
|
22
|
+
:short => '-b BRANCH',
|
23
|
+
:long => '--upstream-branch BRANCH',
|
24
|
+
:description => 'Upstream branch name'
|
25
|
+
|
26
|
+
option :title,
|
27
|
+
:short => '-t TITLE',
|
28
|
+
:long => '--title TITLE',
|
29
|
+
:description => 'Title for pull request'
|
30
|
+
|
31
|
+
option :foodcritic,
|
32
|
+
:short => '-f',
|
33
|
+
:long => '--foodcritic',
|
34
|
+
:description => 'Pass foodcritic before generating pull request',
|
35
|
+
:boolean => true
|
36
|
+
|
37
|
+
option :foodcritic_fail_on,
|
38
|
+
:short => '-x correctness,any,~FC014',
|
39
|
+
:long => '--foodcritic-fail-on correctness,any,~FC014',
|
40
|
+
:description => 'Set what foodcritic should fail on',
|
41
|
+
:proc => lambda{|v| v.split(',').strip}
|
42
|
+
|
43
|
+
|
44
|
+
def run
|
45
|
+
ui.msg ui.highline.color("#{' ' * 10}** Knife Table: Placing Order **", [HighLine::GREEN, HighLine::BOLD])
|
46
|
+
check_config_options
|
47
|
+
if(config[:foodcritic])
|
48
|
+
fail_on = Array(config[:foodcritic_fail_on]).map{|s| "-f #{s}"}.join(' ')
|
49
|
+
cookbooks = discover_changed(:cookbooks, 'master', 'HEAD').map{|c| c.split('/').first}
|
50
|
+
pass = true
|
51
|
+
cookbooks.each do |cookbook|
|
52
|
+
res = system("foodcritic #{fail_on} #{File.join(cookbook_path, cookbook)}")
|
53
|
+
pass = res unless res
|
54
|
+
end
|
55
|
+
unless(pass)
|
56
|
+
ui.fatal "Modifications do not currently pass foodcritic!"
|
57
|
+
exit 1
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# TODO: Update this to not shell out
|
62
|
+
cmd = "hub pull-request \"#{title}\" -b #{@upstream}:#{config[:upstream_branch]} -h #{local_user}:#{local_branch}"
|
63
|
+
output = ''
|
64
|
+
err = nil
|
65
|
+
unless(File.exists?(File.join(ENV['HOME'], '.config', 'hub')))
|
66
|
+
g_config = Hub::GitHubAPI::Configuration.new(nil)
|
67
|
+
g_user = g_config.prompt 'Github username'
|
68
|
+
g_pass = g_config.prompt_password 'Github', g_user
|
69
|
+
end
|
70
|
+
res = Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
|
71
|
+
if(g_user)
|
72
|
+
stdin.puts g_user
|
73
|
+
stdin.puts g_pass
|
74
|
+
end
|
75
|
+
output << stdout.readlines.last.to_s
|
76
|
+
err = stderr.readlines.last.to_s
|
77
|
+
wait_thr.value
|
78
|
+
end
|
79
|
+
output.strip!
|
80
|
+
if(res.success?)
|
81
|
+
ui.msg "New pull request: #{output}"
|
82
|
+
else
|
83
|
+
ui.error err.to_s.empty? ? 'Failed to create pull request' : err
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def title
|
90
|
+
config[:title] || local_branch.gsub('_', ' ')
|
91
|
+
end
|
92
|
+
|
93
|
+
def local_branch
|
94
|
+
unless(@branch)
|
95
|
+
if(name_args.size > 0)
|
96
|
+
@branch = name_args.first
|
97
|
+
else
|
98
|
+
@branch = git.current_branch
|
99
|
+
end
|
100
|
+
end
|
101
|
+
@branch
|
102
|
+
end
|
103
|
+
|
104
|
+
def local_user
|
105
|
+
unless(@local)
|
106
|
+
l = %x{git remote -v}.split("\n").find_all{|r|
|
107
|
+
r.include?('github.com')
|
108
|
+
}.map{|r|
|
109
|
+
Array(r.scan(%r{:[^/]+}).first).first
|
110
|
+
}.compact.map{|r|
|
111
|
+
r.sub(':', '')
|
112
|
+
}.uniq.sort - [@upstream]
|
113
|
+
if(l.size > 1)
|
114
|
+
@local = ask_user_local(l)
|
115
|
+
elsif(l.size < 1)
|
116
|
+
@local = @upstream
|
117
|
+
else
|
118
|
+
@local = l.first
|
119
|
+
end
|
120
|
+
end
|
121
|
+
@local
|
122
|
+
end
|
123
|
+
|
124
|
+
def ask_user_local(locals)
|
125
|
+
l = nil
|
126
|
+
ui.msg 'Please select your local user:'
|
127
|
+
while(l.nil?)
|
128
|
+
locals.each_with_index do |name, idx|
|
129
|
+
ui.msg "#{idx + 1}. #{name}"
|
130
|
+
end
|
131
|
+
res = ui.ask_question "Enter number of local user [1-#{local.size}]:"
|
132
|
+
if(locals[res.to_i + 1])
|
133
|
+
l = locals[res.to_i + 1]
|
134
|
+
else
|
135
|
+
ui.warn "Invalid selection."
|
136
|
+
end
|
137
|
+
end
|
138
|
+
l
|
139
|
+
end
|
140
|
+
|
141
|
+
def check_config_options
|
142
|
+
%w(upstream_user upstream_branch title foodcritic foodcritic_fail_on).each do |key|
|
143
|
+
config[key.to_sym] ||= Chef::Config["table_set_#{key}".to_sym]
|
144
|
+
end
|
145
|
+
@upstream = config[:upstream_user]
|
146
|
+
unless(@upstream)
|
147
|
+
ui.fatal "Upstream user is REQUIRED"
|
148
|
+
exit 1
|
149
|
+
end
|
150
|
+
config[:foodcritic_fail_on] ||= 'correctness'
|
151
|
+
config[:upstream_branch] ||= 'master'
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -32,13 +32,11 @@ module KnifeTable
|
|
32
32
|
option :git_branch,
|
33
33
|
:short => '-b BRANCH',
|
34
34
|
:long => '--git-branch BRANCH',
|
35
|
-
:default => 'master',
|
36
35
|
:description => 'Set working branch'
|
37
36
|
|
38
37
|
option :git_remote_name,
|
39
38
|
:short => '-r NAME',
|
40
39
|
:long => '--git-remote-name NAME',
|
41
|
-
:default => 'origin',
|
42
40
|
:description => 'Remote repo name'
|
43
41
|
|
44
42
|
option :git_autocommit,
|
@@ -65,19 +63,15 @@ module KnifeTable
|
|
65
63
|
:boolean => true,
|
66
64
|
:description => 'Upload any changed data bags'
|
67
65
|
|
68
|
-
def initialize(*args)
|
69
|
-
super
|
70
|
-
@environments = config[:environments].to_s.split(",").map(&:strip)
|
71
|
-
end
|
72
|
-
|
73
66
|
def run
|
67
|
+
check_config_options
|
74
68
|
sanity_checks
|
75
69
|
cookbooks = discover_changed(:cookbooks, *determine_commit_span).map{|c|c.split('/').first}
|
76
70
|
roles = discover_changed(:roles, *determine_commit_span) if config[:upload_roles]
|
77
71
|
data_bags = discover_changed(:data_bags, *determine_commit_span) if config[:upload_data_bags]
|
78
72
|
|
79
73
|
ui.msg ui.highline.color("#{' ' * 10}** Knife Table: Service started **", [HighLine::GREEN, HighLine::BOLD])
|
80
|
-
ui.highline.say ui.highline.color("Discovered cookbooks staged for freeze: #{cookbooks.join(', ')}", HighLine::CYAN)
|
74
|
+
ui.highline.say ui.highline.color("Discovered cookbooks staged for freeze: #{cookbooks.join(', ')}", HighLine::CYAN) unless cookbooks.nil? || cookbooks.empty?
|
81
75
|
ui.highline.say ui.highline.color("Environments staged to be updated: #{@environments.join(', ')}", HighLine::CYAN) unless @environments.empty?
|
82
76
|
ui.highline.say ui.highline.color("Roles staged to be uploaded: #{roles.sort.map{|r|r.sub(/\.(rb|json)/, '')}.join(', ')}", HighLine::CYAN) unless roles.nil? || roles.empty?
|
83
77
|
ui.highline.say ui.highline.color("Data Bags staged to be uploaded: #{data_bags.sort.join(', ')}", HighLine::CYAN) unless data_bags.nil? || data_bags.empty?
|
@@ -224,6 +218,7 @@ module KnifeTable
|
|
224
218
|
def upload_roles(role)
|
225
219
|
role_load = loader(:roles).load_from('roles', role)
|
226
220
|
role_load.save
|
221
|
+
role_load
|
227
222
|
end
|
228
223
|
|
229
224
|
def upload_data_bags(bag)
|
@@ -232,6 +227,7 @@ module KnifeTable
|
|
232
227
|
dbag.data_bag(bag.split('/').first)
|
233
228
|
dbag.raw_data = data_bag_load
|
234
229
|
dbag.save
|
230
|
+
dbag
|
235
231
|
end
|
236
232
|
|
237
233
|
private
|
@@ -297,23 +293,13 @@ module KnifeTable
|
|
297
293
|
end
|
298
294
|
end
|
299
295
|
|
300
|
-
def discover_changed(type, first_commit, last_commit)
|
301
|
-
changed = []
|
302
|
-
git.diff(first_commit, last_commit).stats[:files].keys.each do |path|
|
303
|
-
if(path.start_with?(type.to_s))
|
304
|
-
changed << path.sub(/^#{type.to_s}\/?/, '')
|
305
|
-
end
|
306
|
-
end
|
307
|
-
changed.uniq
|
308
|
-
end
|
309
|
-
|
310
296
|
def upload_changes(type, changed)
|
311
297
|
raise "Unsupported upload change type: #{type}" unless [:roles, :data_bags].include?(type.to_sym)
|
312
298
|
ui.highline.say "#{ui.highline.color("Uploading #{type.to_s.gsub('_', ' ')}:", HighLine::GREEN)} "
|
313
299
|
unless(changed.empty?)
|
314
300
|
changed.each do |item|
|
315
|
-
send("upload_#{type}", item)
|
316
|
-
ui.highline.say "#{
|
301
|
+
thing = send("upload_#{type}", item)
|
302
|
+
ui.highline.say "#{thing.is_a?(Chef::Role) ? thing.name : "#{thing.data_bag}::#{thing.id}"} "
|
317
303
|
end
|
318
304
|
else
|
319
305
|
ui.highline.say "no #{type.to_s.gsub('_', ' ').sub(/s$/, '')} changes detected "
|
@@ -331,5 +317,14 @@ module KnifeTable
|
|
331
317
|
end
|
332
318
|
end
|
333
319
|
|
320
|
+
def check_config_options
|
321
|
+
%w(environments git_autopush git_tag git_branch git_remote_name
|
322
|
+
git_autocommit autoproceed upload_roles upload_data_bags).each do |key|
|
323
|
+
config[key.to_sym] ||= Chef::Config["table_set_#{key}".to_sym]
|
324
|
+
end
|
325
|
+
@environments = config[:environments].to_s.split(",").map(&:strip)
|
326
|
+
config[:git_branch] ||= 'master'
|
327
|
+
config[:git_remote_name] ||= 'origin'
|
328
|
+
end
|
334
329
|
end
|
335
330
|
end
|
data/lib/chef/knife/table_set.rb
CHANGED
@@ -20,23 +20,24 @@ module KnifeTable
|
|
20
20
|
option :branch_prefix,
|
21
21
|
:short => '-p PREFIX',
|
22
22
|
:long => '--branch-prefix PREFIX',
|
23
|
-
:description => 'Set prefix for branch name'
|
24
|
-
:default => 'WIP-'
|
23
|
+
:description => 'Set prefix for branch name'
|
25
24
|
|
26
25
|
option :bump_type,
|
27
26
|
:short => '-b TYPE',
|
28
27
|
:long => '--bump-type TYPE',
|
29
|
-
:description => 'Type of version bump (major, minor, patch)'
|
30
|
-
:default => 'patch'
|
31
|
-
|
32
|
-
def initialize(*args)
|
33
|
-
super
|
34
|
-
@cookbooks = config[:cookbooks].to_s.split(',').map(&:strip)
|
35
|
-
end
|
28
|
+
:description => 'Type of version bump (major, minor, patch)'
|
36
29
|
|
37
30
|
def run
|
38
31
|
ui.msg ui.highline.color("#{' ' * 10}** Knife Table: New place setting **", [HighLine::GREEN, HighLine::BOLD])
|
32
|
+
if(name_args.empty?)
|
33
|
+
ui.fatal "Feature description must be provided"
|
34
|
+
exit 1
|
35
|
+
end
|
36
|
+
check_config_options
|
37
|
+
check_current_branch!
|
38
|
+
check_up_to_date!
|
39
39
|
branch_name = "#{config[:branch_prefix]}#{name_args.join('_').downcase}"
|
40
|
+
check_branch_conflict!(branch_name)
|
40
41
|
ui.highline.say "Creating new work branch (#{branch_name}): "
|
41
42
|
git.branch(branch_name).create
|
42
43
|
ui.highline.say "done"
|
@@ -50,5 +51,36 @@ module KnifeTable
|
|
50
51
|
end
|
51
52
|
end
|
52
53
|
|
54
|
+
private
|
55
|
+
|
56
|
+
def check_current_branch!
|
57
|
+
unless(git.current_branch == 'master')
|
58
|
+
ui.fatal "Set requires master branch to be checked out. Currently on: #{git.current_branch}"
|
59
|
+
exit 1
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def check_branch_conflict!(name)
|
64
|
+
conflict = git.branches.map(&:full).detect do |b|
|
65
|
+
b == name || b.sub(%r{remotes/[^/]+/}, '') == name
|
66
|
+
end
|
67
|
+
if(conflict)
|
68
|
+
ui.fatal "Failed to create topic branch. Already exists: #{conflict}"
|
69
|
+
exit 1
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def check_up_to_date!
|
74
|
+
# TODO: fetch/merge master to ensure up to date?
|
75
|
+
end
|
76
|
+
|
77
|
+
def check_config_options
|
78
|
+
%w(cookbooks branch_prefix bump_type).each do |key|
|
79
|
+
config[key.to_sym] ||= Chef::Config["table_set_#{key}".to_sym]
|
80
|
+
end
|
81
|
+
@cookbooks = config[:cookbooks].to_s.split(',').map(&:strip)
|
82
|
+
config[:bump_type] ||= 'patch'
|
83
|
+
end
|
84
|
+
|
53
85
|
end
|
54
86
|
end
|
data/lib/knife-table/helpers.rb
CHANGED
@@ -7,5 +7,15 @@ module KnifeTable
|
|
7
7
|
def cookbook_path
|
8
8
|
Chef::Config[:cookbook_path].first
|
9
9
|
end
|
10
|
+
|
11
|
+
def discover_changed(type, first_commit, last_commit)
|
12
|
+
changed = []
|
13
|
+
git.diff(first_commit, last_commit).stats[:files].keys.each do |path|
|
14
|
+
if(path.start_with?(type.to_s))
|
15
|
+
changed << path.sub(/^#{type.to_s}\/?/, '')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
changed.uniq
|
19
|
+
end
|
10
20
|
end
|
11
21
|
end
|
data/lib/knife-table/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: knife-table
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,32 +9,54 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-07-
|
12
|
+
date: 2012-07-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: knife-spork
|
16
|
-
requirement: &
|
16
|
+
requirement: &5700840 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
21
|
+
version: 0.1.11
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *5700840
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: hub
|
27
|
+
requirement: &5716660 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.10.1
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *5716660
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: foodcritic
|
38
|
+
requirement: &5716120 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.4.0
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *5716120
|
25
47
|
description: Chef's table
|
26
48
|
email: chrisroberts.code@gmail.com
|
27
49
|
executables: []
|
28
50
|
extensions: []
|
29
51
|
extra_rdoc_files: []
|
30
52
|
files:
|
53
|
+
- knife-table-0.0.3.gem
|
31
54
|
- CHANGELOG.md
|
32
|
-
- knife-table-0.0.2.gem
|
33
55
|
- README.md
|
34
56
|
- knife-table.gemspec
|
35
57
|
- lib/knife-table/version.rb
|
36
58
|
- lib/knife-table/helpers.rb
|
37
|
-
- lib/chef/knife/
|
59
|
+
- lib/chef/knife/table_order.rb
|
38
60
|
- lib/chef/knife/table_serve.rb
|
39
61
|
- lib/chef/knife/table_clear.rb
|
40
62
|
- lib/chef/knife/table_set.rb
|
@@ -1,54 +0,0 @@
|
|
1
|
-
require 'pp'
|
2
|
-
|
3
|
-
class DataHolder
|
4
|
-
|
5
|
-
def initialize
|
6
|
-
@holder = {}
|
7
|
-
@path = nil
|
8
|
-
end
|
9
|
-
|
10
|
-
def method_missing(name, *args)
|
11
|
-
@holder[name] = args
|
12
|
-
end
|
13
|
-
|
14
|
-
def ==(holder)
|
15
|
-
raise TypeError.new('Comparisons only allowed between DataHolder instances')
|
16
|
-
self._holder == holder._holder
|
17
|
-
end
|
18
|
-
|
19
|
-
def _holder
|
20
|
-
@holder
|
21
|
-
end
|
22
|
-
|
23
|
-
def _load(path)
|
24
|
-
@path = path
|
25
|
-
self.instance_eval(
|
26
|
-
File.read(path)
|
27
|
-
)
|
28
|
-
self
|
29
|
-
end
|
30
|
-
|
31
|
-
def _output
|
32
|
-
output = ''
|
33
|
-
@holder.each_pair do |k,v|
|
34
|
-
output << "#{k}(\n"
|
35
|
-
inards = []
|
36
|
-
v.each do |item|
|
37
|
-
s = ''
|
38
|
-
PP.pp(item, s)
|
39
|
-
inards << s
|
40
|
-
end
|
41
|
-
output << inards.join(",\n")
|
42
|
-
output << ")\n"
|
43
|
-
end
|
44
|
-
output
|
45
|
-
File.open(@path, 'w') do |file|
|
46
|
-
file.write(output)
|
47
|
-
end
|
48
|
-
output
|
49
|
-
end
|
50
|
-
|
51
|
-
def _path
|
52
|
-
@path
|
53
|
-
end
|
54
|
-
end
|