knife-table 0.0.2 → 0.0.3
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/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
|