luigi 1.0.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 31f72e1bb7c69d75d612950916f95e58fa4400aa
4
+ data.tar.gz: 5ef3d3525cc4fed1a18e116f2a181b0404345824
5
+ SHA512:
6
+ metadata.gz: 36b695ae7932032f603148293248e81783306009f32fcf88aa9c0bc151987cb84cfb635114e8b5fb4129d55b920c3beb97543f5a14139770dc4803bbfea22073
7
+ data.tar.gz: 5a90dce275ef2342a929b19c05387d581f5b51e171e336efc2c9ff7e7c386bfbaed2106b3a6a4ef7602935d58924ae693035a4f0f87027335389e7da6ae5fb5f
@@ -0,0 +1,34 @@
1
+ require 'date'
2
+
3
+ #interface
4
+ class PlumberProject
5
+
6
+ def initialize path
7
+ open path
8
+ end
9
+
10
+ def open path
11
+ @path = path
12
+ end
13
+
14
+ def path
15
+ @path
16
+ end
17
+
18
+ def name
19
+ File.basename @path, ".yml"
20
+ end
21
+
22
+ def index
23
+ 123
24
+ end
25
+
26
+ def STATUS
27
+ :ok # at least :ok or anything else
28
+ end
29
+
30
+ def date
31
+ return Date.today
32
+
33
+ end
34
+ end
@@ -0,0 +1,396 @@
1
+ # encoding: utf-8
2
+ require 'fileutils'
3
+ require 'logger'
4
+
5
+ require File.join File.dirname(__FILE__), "luigi/gitplumber"
6
+ require File.join File.dirname(__FILE__), "luigi/ShellSanitizer"
7
+
8
+ ## requires a project_class
9
+ # project_class must implement: name, date
10
+ class Luigi
11
+
12
+ attr_reader :dirs,
13
+ :opened_projects,
14
+ :project_paths,
15
+ :opened_paths,
16
+ :opened_sort,
17
+ :opened_dir
18
+
19
+ attr_writer :project_class
20
+
21
+ include GitPlumber
22
+
23
+
24
+ def initialize(settings, project_class = nil)
25
+ @settings = settings
26
+ @opened_projects = []
27
+ @project_class = project_class
28
+ @file_extension = settings['project_file_extension']
29
+ @using_git = settings['use_git']
30
+
31
+ @logger = Logger.new(STDERR)
32
+ @logger.level = Logger::ERROR
33
+ @logger.error "need a project_class" if project_class.nil?
34
+ @logger.progname = "LUIGI"
35
+
36
+ @dirs = {}
37
+ # TODO allow for multiple templates
38
+ @dirs[:template] = File.expand_path File.join @settings['script_path'], @settings['templates']['project']
39
+ @dirs[:storage] = File.expand_path File.join @settings['path'], @settings['dirs']['storage']
40
+ @dirs[:working] = File.join @dirs[:storage], @settings['dirs']['working']
41
+ @dirs[:archive] = File.join @dirs[:storage], @settings['dirs']['archive']
42
+
43
+
44
+ end
45
+
46
+ ##
47
+ # Checks the existens of one of the three basic dirs.
48
+ # dir can be either :storage, :working or :archive
49
+ # and also :template
50
+ def check_dir(dir)
51
+ File.exists? "#{@dirs[dir]}"
52
+ end
53
+
54
+ ##
55
+ # Checks the existens of every thing required
56
+ def check_dirs
57
+ check_dir :storage and
58
+ check_dir :working and
59
+ check_dir :archive and
60
+ check_dir :template
61
+ end
62
+
63
+ ##
64
+ # create a dir
65
+ # dir can be either :storage, :working or :archive
66
+ def create_dir(dir)
67
+ unless check_dir(dir)
68
+ if dir == :storage or check_dir :storage
69
+ FileUtils.mkdir "#{@dirs[dir]}"
70
+ @logger.info "Created \"#{dir.to_s}\" Directory (#{@dirs[dir]})"
71
+ return true
72
+ end
73
+ @logger.error "no storage dir"
74
+ end
75
+ return false
76
+ end
77
+
78
+ ##
79
+ # creates new project_dir and project_file
80
+ def _new_project_folder(name)
81
+ unless check_dir(:working)
82
+ @logger.info(File.exists? @dirs[:working])
83
+ @logger.info "missing working directory!"
84
+ return false
85
+ end
86
+
87
+ # check of existing project with the same name
88
+ folder = get_project_folder(name, :working)
89
+ unless folder
90
+ FileUtils.mkdir File.join @dirs[:working], name
91
+ return get_project_folder(name, :working)
92
+ else
93
+ @logger.info "#{folder} already exists"
94
+ return false
95
+ end
96
+ end
97
+
98
+ ##
99
+ # creates new project_dir and project_file
100
+ # returns project object
101
+ def new_project(_name)
102
+ _name = ShellSanitizer.process _name
103
+ name = ShellSanitizer.clean_path _name
104
+
105
+ project_name = _name
106
+ settings = @settings
107
+ defaults = @settings['defaults']
108
+ defaults = {}
109
+
110
+ filename = @dirs[:template]
111
+
112
+ ## Approach A ( Thomas Kühn )
113
+ engine=ERB.new(File.read(filename),nil,'<>')
114
+ result = engine.result(binding)
115
+
116
+ # copy template_file to project_dir
117
+ folder = _new_project_folder(name)
118
+ if folder
119
+ target = File.join folder, name+@file_extension
120
+
121
+ #puts "writing into #{target}"
122
+ file = File.new target, "w"
123
+ result.lines.each do |line|
124
+ file.write line
125
+ end
126
+ file.close
127
+
128
+ @logger.info "#{folder} created"
129
+ return @project_class.new target
130
+ else
131
+ return false
132
+ end
133
+ end
134
+
135
+
136
+ ##
137
+ # produces an Array of @project_class objects
138
+ # sorted by date (projects must implement date())
139
+ # if sort is foobar, projects must implement foobar()
140
+ # output of (foobar must be comparable)
141
+ #
142
+ # untested
143
+ def open_projects(dir=:working, year=Date.today.year, sort = :date)
144
+ if dir==:all
145
+ @opened_paths = list_projects_all
146
+ else
147
+ @opened_paths = list_projects dir, year
148
+ end
149
+
150
+ @opened_dir = dir
151
+ @project_paths = {}
152
+ @opened_paths.each {|path|
153
+ project = @project_class.new path
154
+ if project.STATUS == :ok
155
+ @opened_projects = @opened_projects + [ project ]
156
+ end
157
+ @project_paths[project.name] = path
158
+ }
159
+ sort_projects(sort)
160
+ return true
161
+ end
162
+
163
+ def open_project project
164
+ if project.class == String
165
+ project = ShellSanitizer.process project
166
+ project = ShellSanitizer.clean_path project
167
+ open_projects()
168
+ project = lookup(project)
169
+ end
170
+ return project if project.class == @project_class
171
+ return false
172
+ end
173
+
174
+
175
+ ##
176
+ # produces an Array of @project_class objects
177
+ #
178
+ # untested
179
+ def open_projects_all(sort = :date)
180
+ @opened_paths = list_projects_all
181
+ open_projects :all, year=nil, sort
182
+ end
183
+
184
+ def [] name
185
+ lookup name
186
+ end
187
+
188
+ def lookup_path(name, sort = nil)
189
+ p = lookup(name)
190
+ return @project_paths[p.name] unless p.nil?
191
+ @logger.error "there is no project #{name}"
192
+ return false
193
+ end
194
+
195
+
196
+ def lookup(name, sort = nil)
197
+ sort_projects sort unless sort == nil or @opened_sort == sort
198
+ name = name.to_i - 1 if name =~ /^\d*$/
199
+ if name.class == String
200
+ name_map = {}
201
+ @opened_projects.each {|project| name_map[project.name] = project}
202
+ project = name_map[name]
203
+ @logger.error "there is no project \"#{name}\"" if project.nil?
204
+ elsif name.class == Fixnum
205
+ project = @opened_projects[name]
206
+ @logger.error "there is no project ##{name+1}" if project.nil?
207
+ end
208
+ return project
209
+ end
210
+
211
+
212
+ def sort_projects(sort = :date)
213
+ fail "sort must be a Symbol" unless sort.class == Symbol
214
+ if @project_class.method_defined? sort
215
+ @opened_projects.sort_by! {|project| project.method(sort).call}
216
+ else fail "#{@project_class} does not implement #{sort}()"
217
+ end
218
+ return true
219
+ end
220
+
221
+ ##
222
+ # path to project file
223
+ # there may only be one @file_extension file per project folder
224
+ #
225
+ # untested
226
+ def get_project_file_path(name, dir=:working, year=Date.today.year)
227
+ name = ShellSanitizer.process name
228
+ name = ShellSanitizer.clean_path name
229
+
230
+ folder = get_project_folder(name, dir, year)
231
+ if folder
232
+ files = Dir.glob File.join folder, "*#{@file_extension}"
233
+ warn "ambiguous amount of #{@file_extension} files in #{folder}" if files.length > 1
234
+ warn "no #{@file_extension} files in #{folder}" if files.length < 1
235
+ return files[0]
236
+ end
237
+ @logger.info "NO FOLDER get_project_folder(name = #{name}, dir = #{dir}, year = #{year})"
238
+ return false
239
+ end
240
+
241
+
242
+ ##
243
+ # Path to project folder
244
+ # If the folder exists
245
+ # dir can be :working or :archive
246
+ #
247
+ # TODO untested for archives
248
+ def get_project_folder( name, dir=:working, year=Date.today.year )
249
+ name = ShellSanitizer.process name
250
+ name = ShellSanitizer.clean_path name
251
+ year = year.to_s
252
+ target = File.join @dirs[dir], name if dir == :working
253
+ target = File.join @dirs[dir], year, name if dir == :archive
254
+ return target if File.exists? target
255
+ false
256
+ end
257
+
258
+ ##
259
+ # list projects
260
+ # lists project files
261
+ def list_project_names(dir = :working, year=Date.today.year)
262
+ return unless check_dir(dir)
263
+ if dir == :working
264
+ paths = Dir.glob File.join @dirs[dir], "/*"
265
+ names = paths.map {|path| File.basename path }
266
+ elsif dir == :archive
267
+ paths = Dir.glob File.join @dirs[dir], year.to_s, "/*"
268
+ names = paths.map {|path|
269
+ file_path = get_project_file_path (File.basename path), :archive, year
270
+ name = File.basename file_path, @file_extension
271
+ }
272
+ return names
273
+ else
274
+ @logger.error "unknown path #{dir}"
275
+ end
276
+ end
277
+
278
+ ##
279
+ # list projects
280
+ # lists project files
281
+ # (names actually contains paths)
282
+ def list_projects(dir = :working, year=Date.today.year)
283
+ return unless check_dir(dir)
284
+ if dir == :working
285
+ folders = Dir.glob File.join @dirs[dir], "/*"
286
+ paths = folders.map {|path| get_project_file_path File.basename path }
287
+ elsif dir == :archive
288
+ folders = Dir.glob File.join @dirs[dir], year.to_s, "/*"
289
+ paths = folders.map {|path| get_project_file_path (File.basename path), :archive, year }
290
+ else
291
+ @logger.error "unknown path #{dir}"
292
+ end
293
+
294
+ puts "WARNING! one folder is not correct" if paths.include? false
295
+ paths.keep_if{|v| v}
296
+ end
297
+
298
+ ##
299
+ # list projects
300
+ # lists project files
301
+ # (names actually contains paths)
302
+ def list_projects_all
303
+ names = []
304
+
305
+ #first all archived projects, ever :D
306
+ archives = Dir.glob File.join @dirs[:archive], "/*"
307
+ archives.sort!
308
+ archives.each do |a|
309
+ paths = Dir.glob File.join a, "/*"
310
+ year = File.basename a
311
+ names += paths.map { |path|
312
+ get_project_file_path (File.basename path), :archive, year
313
+ }
314
+ end
315
+
316
+ #then all working projects
317
+ names += list_projects :working
318
+
319
+ return names
320
+ end
321
+
322
+ def filter_by hash
323
+ filtered_projets = []
324
+ @opened_projects.each{|project|
325
+ hash.each{|key,value|
326
+ field = project.data(key)
327
+ if field and field.to_s.downcase.include? value
328
+ filtered_projets.push project
329
+ break
330
+ end
331
+ }
332
+ }
333
+ return filtered_projets
334
+ end
335
+
336
+ ##
337
+ # Move to archive directory
338
+ # @name
339
+ ## Luigi.archive_project should use ShellSanitizer
340
+ def archive_project(project, year = nil, prefix = '')
341
+ project = open_project project
342
+ return false unless project.class == @project_class
343
+
344
+ year ||= project.date.year
345
+ year_folder = File.join @dirs[:archive], year.to_s
346
+ FileUtils.mkdir year_folder unless File.exists? year_folder
347
+
348
+ project_folder = get_project_folder project.name, :working
349
+ if prefix and prefix.length > 0
350
+ archived_name = project.name.prepend(prefix + "_")
351
+ target = File.join year_folder, archived_name
352
+ else
353
+ target = File.join year_folder, project.name
354
+ end
355
+
356
+ return false unless project_folder
357
+ return false if list_project_names(:archive, year).include? project.name
358
+
359
+ @logger.info "moving: #{project_folder} to #{target}" if target and project_folder
360
+
361
+ FileUtils.mv project_folder, target
362
+ if open_git()
363
+ git_update_path project_folder
364
+ git_update_path target
365
+ end
366
+ return target
367
+ end
368
+
369
+ ##
370
+ # Move to archive directory
371
+ def unarchive_project(project, year = Date.today.year)
372
+ project = open_project project
373
+ return false unless project.class == @project_class
374
+
375
+ name = project.name
376
+ path = project.path
377
+ cleaned_name = File.basename(path,@file_extension)
378
+ source = get_project_folder name, :archive, year
379
+ target = File.join @dirs[:working], cleaned_name
380
+
381
+ @logger.info "moving #{source} to #{target}"
382
+ return false unless source
383
+
384
+ unless get_project_folder cleaned_name
385
+ FileUtils.mv source, target
386
+ if open_git()
387
+ git_update_path source
388
+ git_update_path target
389
+ end
390
+ return true
391
+ else
392
+ return false
393
+ end
394
+ end
395
+
396
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ class ShellSanitizer
4
+ REPLACE_HASH = {
5
+ ?“ => '"', ?” => '"', ?‘ => "'", ?’ => "'", ?„ => '"',
6
+
7
+ ?» => ">>", ?« => "<<",
8
+ ?ä => "ae", ?ö => "oe", ?ü => "ue",
9
+ ?Ä => "Ae", ?Ö => "Oe", ?Ü => "Ue",
10
+ ?ß => "ss", ?ï => "i", ?ë => "e",
11
+ ?æ => "ae", ?Æ => "AE", ?œ => "oe",
12
+ ?Œ => "OE",
13
+ ?€ => "EUR", ?¥ => "YEN",
14
+ ?½ => "1/2", ?¼ => "1/4", ?¾ => "3/4",
15
+ ?© => "(c)", ?™ => "(TM)", ?® => "(r)",
16
+ ?♥ => "<3", ?☺ => ":)"
17
+ }
18
+
19
+ def self.process(string)
20
+ string = deumlautify string
21
+ #string = Ascii.process string
22
+ return string
23
+ end
24
+
25
+ ## TODO somebody find my a gem that works and I'll replace this
26
+ def self.deumlautify(string)
27
+ REPLACE_HASH.each{|k,v| string = string.gsub k, v }
28
+ string.each_char.to_a.keep_if {|c| c.ascii_only?}
29
+ return string
30
+ end
31
+
32
+ def self.clean_path(path)
33
+ path = path.strip()
34
+ path = deumlautify path
35
+ path.sub!(/^\./,'') # removes hidden_file_dot '.' from the begging
36
+ path.gsub!(/\//,'_')
37
+ path.gsub!(/\//,'_')
38
+ return path
39
+ end
40
+
41
+ end
@@ -0,0 +1,151 @@
1
+ # encoding: utf-8
2
+
3
+ # # http://stackoverflow.com/questions/1891429/decorators-in-ruby-migrating-from-python
4
+ # module Documenter
5
+ # def document(func_name)
6
+ # old_method = instance_method(func_name)
7
+ #
8
+ # define_method(func_name) do |*args|
9
+ # puts "about to call #{func_name}(#{args.join(', ')})"
10
+ # old_method.bind(self).call(*args)
11
+ # end
12
+ # end
13
+ # end
14
+
15
+ require 'git'
16
+ require 'logger'
17
+ require 'textboxes'
18
+
19
+ module GitPlumber
20
+
21
+ def open_git
22
+ return false unless @using_git
23
+ logger = Logger.new STDOUT
24
+ begin
25
+ @git = Git.open @dirs[:storage]
26
+ return true
27
+ rescue => error
28
+ logger.error "#{@dirs[:storage]} does not seem to be a git repository"
29
+ return false
30
+ end
31
+ end
32
+
33
+ def git_log(count = 30)
34
+ table = Textboxes.new
35
+ table.style[:border] = false
36
+ @git.log(count = count).to_a.reverse.each do |commit|
37
+ table.add_row [
38
+ commit.author.name,
39
+ commit.message,
40
+ commit.date.strftime("%H:%M Uhr — %d.%m.%Y"),
41
+ ]
42
+ end
43
+ puts table
44
+ end
45
+
46
+ def git_push()
47
+ @git = Git.open @dirs[:storage], :log => Logger.new(STDOUT)
48
+ out = @git.push()
49
+ puts out if out
50
+ end
51
+
52
+ def git_pull()
53
+ @git = Git.open @dirs[:storage], :log => Logger.new(STDOUT)
54
+ out = @git.pull()
55
+ puts out if out
56
+ end
57
+
58
+ def git_commit(message)
59
+ @git.commit(message)
60
+ end
61
+
62
+ def git_update_path path = @git.dir
63
+ return unless @settings['use_git']
64
+ if File.exists? path
65
+ @git.add path
66
+ else
67
+ @git.remove path, {:recursive => true}
68
+ end
69
+
70
+ end
71
+
72
+ def git_save message
73
+ puts "GITSAVE\n"
74
+ git_add()
75
+ @git.commit_all "ruby git #commit_all \"#{message}\""
76
+ end
77
+
78
+ def git_status
79
+ renamed = git_renamed_files
80
+ exclude = renamed.flatten
81
+ if @git.status.added.length + @git.status.deleted.length + @git.status.untracked.length + @git.status.changed.length == 0
82
+ puts "Nothing Changed"
83
+ end
84
+
85
+ git_print_status :added, exclude
86
+ git_print_status :changed, exclude
87
+ git_print_status :deleted, exclude
88
+ git_print_status :untracked, exclude
89
+ git_print_renamed renamed
90
+ end
91
+
92
+ def git_print_status name, exclude
93
+ case name
94
+ when :added then status = @git.status.added
95
+ when :changed then status = @git.status.changed
96
+ when :deleted then status = @git.status.deleted
97
+ when :untracked then status = @git.status.untracked
98
+ end
99
+ status.reject! {|k,v| exclude.include? k }
100
+
101
+ puts "#{status.length} #{name.to_s.capitalize}:" if status.length > 0
102
+ status.each do |path, info|
103
+ case info.type
104
+ when "M" then color = :yellow
105
+ when "A" then color = :green
106
+ when "D" then color = :red
107
+ else color = :default
108
+ end
109
+ line = Paint[path, color]
110
+ state = " "
111
+ state = Paint[ "\e[32m✓\e[0m" , :green] if !info.sha_index.nil? and info.sha_index.to_i(16) > 0
112
+ puts "#{state} #{line}"
113
+ end
114
+ puts if status.length > 0
115
+ end
116
+
117
+ def git_renamed_files
118
+ repo_shas = {}
119
+ index_shas = {}
120
+ out = ""
121
+ files = []
122
+ @git.lib.diff_index('HEAD').each { |file, data|
123
+ sr = data[:sha_repo]
124
+ si = data[:sha_index]
125
+ repo_shas[sr] = file if sr.to_i(16) > 0
126
+ index_shas[si] = file if si.to_i(16) > 0
127
+ if index_shas.include? sr
128
+ files.push [ repo_shas[sr], index_shas[sr] ]
129
+ end
130
+ }
131
+ return files
132
+ end
133
+
134
+ def git_print_renamed files
135
+ puts "#{files.length} Renamed:" if files.length > 0
136
+ width = 0
137
+ files.map {|a,b| width = a.length if a.length > width}
138
+ out = ""
139
+ files.each {|a,b|
140
+ a = a.ljust(width)
141
+ out << Paint[ "\e[32m✓\e[0m" , :green] + " "
142
+ out << Paint[a, :red]
143
+ out << " -> "
144
+ out << Paint[b, :green]
145
+ out << "\n"
146
+ }
147
+ puts out if out.length > 0
148
+ end
149
+
150
+
151
+ end
@@ -0,0 +1,3 @@
1
+ module Luigi
2
+ VERSION = '1.0.0'
3
+ end
metadata ADDED
@@ -0,0 +1,124 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: luigi
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Hendrik Sollich
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec-core
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: git
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.2'
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 1.2.8
65
+ type: :runtime
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - "~>"
70
+ - !ruby/object:Gem::Version
71
+ version: '1.2'
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 1.2.8
75
+ - !ruby/object:Gem::Dependency
76
+ name: textboxes
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: 0.0.1
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: 0.0.1
89
+ description: ''
90
+ email: hendrik@hoodie.de
91
+ executables: []
92
+ extensions: []
93
+ extra_rdoc_files: []
94
+ files:
95
+ - lib/PlumberProject.rb
96
+ - lib/luigi.rb
97
+ - lib/luigi/ShellSanitizer.rb
98
+ - lib/luigi/gitplumber.rb
99
+ - lib/luigi/version.rb
100
+ homepage: https://github.com/hoodie/luigi
101
+ licenses:
102
+ - GPL
103
+ metadata: {}
104
+ post_install_message:
105
+ rdoc_options: []
106
+ require_paths:
107
+ - lib
108
+ required_ruby_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '1.9'
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ requirements: []
119
+ rubyforge_project:
120
+ rubygems_version: 2.2.2
121
+ signing_key:
122
+ specification_version: 4
123
+ summary: luigi - a plumber
124
+ test_files: []