ledis 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/README.md +56 -0
  2. data/Rakefile +374 -0
  3. data/ledis.gemspec +29 -0
  4. data/lib/ledis.rb +259 -0
  5. metadata +48 -0
@@ -0,0 +1,56 @@
1
+ NAME
2
+
3
+ ledis
4
+
5
+
6
+ SYNOPSIS
7
+
8
+ a K.I.S.S auto-rotating redis logger for ruby/rails
9
+
10
+ Ruby
11
+
12
+ redis = Redis.new
13
+
14
+ logger = Ledis.logger redis
15
+
16
+ logger = Ledis.new
17
+
18
+ logger = Ledis.new do |config|
19
+
20
+ config.redis = Redis.new
21
+
22
+ config.list = 'teh_foo:log'
23
+
24
+ config.cap = 2 ** 16
25
+
26
+ end
27
+
28
+ Rails
29
+
30
+ ### file: config/environments/development.rb
31
+
32
+ config.logger = Ledis.logger do |logger|
33
+
34
+ logger.list = "teh_rails_app:#{ Rails.env }:log"
35
+
36
+ end
37
+
38
+
39
+ DESCRIPTION
40
+
41
+ ledis logs yo shiznit to redis. it's got built in logic to auto-truncate
42
+ logs when they get to big
43
+
44
+ logger.truncate(2 **16)
45
+
46
+ and to grab the most recent ones
47
+
48
+ puts logger.tail(1024)
49
+
50
+ it's list/line oriented, just like a log file and makes no attempt to
51
+ annotated log lines or add fancy data structures to them
52
+
53
+ INSTALL
54
+
55
+ gem 'ledis'
56
+
@@ -0,0 +1,374 @@
1
+ This.rubyforge_project = 'codeforpeople'
2
+ This.author = "Ara T. Howard"
3
+ This.email = "ara.t.howard@gmail.com"
4
+ This.homepage = "https://github.com/ahoward/#{ This.lib }"
5
+
6
+ task :license do
7
+ open('LICENSE', 'w'){|fd| fd.puts "same as ruby's"}
8
+ end
9
+
10
+ task :default do
11
+ puts((Rake::Task.tasks.map{|task| task.name.gsub(/::/,':')} - ['default']).sort)
12
+ end
13
+
14
+ task :test do
15
+ run_tests!
16
+ end
17
+
18
+ namespace :test do
19
+ task(:unit){ run_tests!(:unit) }
20
+ task(:functional){ run_tests!(:functional) }
21
+ task(:integration){ run_tests!(:integration) }
22
+ end
23
+
24
+ def run_tests!(which = nil)
25
+ which ||= '**'
26
+ test_dir = File.join(This.dir, "test")
27
+ test_glob ||= File.join(test_dir, "#{ which }/**_test.rb")
28
+ test_rbs = Dir.glob(test_glob).sort
29
+
30
+ div = ('=' * 119)
31
+ line = ('-' * 119)
32
+
33
+ test_rbs.each_with_index do |test_rb, index|
34
+ testno = index + 1
35
+ command = "#{ This.ruby } -I ./lib -I ./test/lib #{ test_rb }"
36
+
37
+ puts
38
+ say(div, :color => :cyan, :bold => true)
39
+ say("@#{ testno } => ", :bold => true, :method => :print)
40
+ say(command, :color => :cyan, :bold => true)
41
+ say(line, :color => :cyan, :bold => true)
42
+
43
+ system(command)
44
+
45
+ say(line, :color => :cyan, :bold => true)
46
+
47
+ status = $?.exitstatus
48
+
49
+ if status.zero?
50
+ say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
51
+ say("SUCCESS", :color => :green, :bold => true)
52
+ else
53
+ say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
54
+ say("FAILURE", :color => :red, :bold => true)
55
+ end
56
+ say(line, :color => :cyan, :bold => true)
57
+
58
+ exit(status) unless status.zero?
59
+ end
60
+ end
61
+
62
+
63
+ task :gemspec do
64
+ ignore_extensions = ['git', 'svn', 'tmp', /sw./, 'bak', 'gem']
65
+ ignore_directories = ['pkg']
66
+ ignore_files = ['test/log']
67
+
68
+ shiteless =
69
+ lambda do |list|
70
+ list.delete_if do |entry|
71
+ next unless test(?e, entry)
72
+ extension = File.basename(entry).split(%r/[.]/).last
73
+ ignore_extensions.any?{|ext| ext === extension}
74
+ end
75
+ list.delete_if do |entry|
76
+ next unless test(?d, entry)
77
+ dirname = File.expand_path(entry)
78
+ ignore_directories.any?{|dir| File.expand_path(dir) == dirname}
79
+ end
80
+ list.delete_if do |entry|
81
+ next unless test(?f, entry)
82
+ filename = File.expand_path(entry)
83
+ ignore_files.any?{|file| File.expand_path(file) == filename}
84
+ end
85
+ end
86
+
87
+ lib = This.lib
88
+ object = This.object
89
+ version = This.version
90
+ files = shiteless[Dir::glob("**/**")]
91
+ executables = shiteless[Dir::glob("bin/*")].map{|exe| File.basename(exe)}
92
+ #has_rdoc = true #File.exist?('doc')
93
+ test_files = "test/#{ lib }.rb" if File.file?("test/#{ lib }.rb")
94
+ summary = object.respond_to?(:summary) ? object.summary : "summary: #{ lib } kicks the ass"
95
+ description = object.respond_to?(:description) ? object.description : "description: #{ lib } kicks the ass"
96
+
97
+ if This.extensions.nil?
98
+ This.extensions = []
99
+ extensions = This.extensions
100
+ %w( Makefile configure extconf.rb ).each do |ext|
101
+ extensions << ext if File.exists?(ext)
102
+ end
103
+ end
104
+ extensions = [extensions].flatten.compact
105
+
106
+ template =
107
+ if test(?e, 'gemspec.erb')
108
+ Template{ IO.read('gemspec.erb') }
109
+ else
110
+ Template {
111
+ <<-__
112
+ ## #{ lib }.gemspec
113
+ #
114
+
115
+ Gem::Specification::new do |spec|
116
+ spec.name = #{ lib.inspect }
117
+ spec.version = #{ version.inspect }
118
+ spec.platform = Gem::Platform::RUBY
119
+ spec.summary = #{ lib.inspect }
120
+ spec.description = #{ description.inspect }
121
+
122
+ spec.files =\n#{ files.sort.pretty_inspect }
123
+ spec.executables = #{ executables.inspect }
124
+
125
+ spec.require_path = "lib"
126
+
127
+ spec.test_files = #{ test_files.inspect }
128
+
129
+ ### spec.add_dependency 'lib', '>= version'
130
+ #### spec.add_dependency 'map'
131
+
132
+ spec.extensions.push(*#{ extensions.inspect })
133
+
134
+ spec.rubyforge_project = #{ This.rubyforge_project.inspect }
135
+ spec.author = #{ This.author.inspect }
136
+ spec.email = #{ This.email.inspect }
137
+ spec.homepage = #{ This.homepage.inspect }
138
+ end
139
+ __
140
+ }
141
+ end
142
+
143
+ Fu.mkdir_p(This.pkgdir)
144
+ gemspec = "#{ lib }.gemspec"
145
+ open(gemspec, "w"){|fd| fd.puts(template)}
146
+ This.gemspec = gemspec
147
+ end
148
+
149
+ task :gem => [:clean, :gemspec] do
150
+ Fu.mkdir_p(This.pkgdir)
151
+ before = Dir['*.gem']
152
+ cmd = "gem build #{ This.gemspec }"
153
+ `#{ cmd }`
154
+ after = Dir['*.gem']
155
+ gem = ((after - before).first || after.first) or abort('no gem!')
156
+ Fu.mv(gem, This.pkgdir)
157
+ This.gem = File.join(This.pkgdir, File.basename(gem))
158
+ end
159
+
160
+ task :readme do
161
+ samples = ''
162
+ prompt = '~ > '
163
+ lib = This.lib
164
+ version = This.version
165
+
166
+ Dir['sample*/*'].sort.each do |sample|
167
+ samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
168
+
169
+ cmd = "cat #{ sample }"
170
+ samples << Util.indent(prompt + cmd, 2) << "\n\n"
171
+ samples << Util.indent(`#{ cmd }`, 4) << "\n"
172
+
173
+ cmd = "ruby #{ sample }"
174
+ samples << Util.indent(prompt + cmd, 2) << "\n\n"
175
+
176
+ cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -I ./lib #{ sample })'"
177
+ samples << Util.indent(`#{ cmd } 2>&1`, 4) << "\n"
178
+ end
179
+
180
+ template =
181
+ if test(?e, 'readme.erb')
182
+ Template{ IO.read('readme.erb') }
183
+ else
184
+ Template {
185
+ <<-__
186
+ NAME
187
+ #{ lib }
188
+
189
+ DESCRIPTION
190
+
191
+ INSTALL
192
+ gem install #{ lib }
193
+
194
+ SAMPLES
195
+ #{ samples }
196
+ __
197
+ }
198
+ end
199
+
200
+ open("README", "w"){|fd| fd.puts template}
201
+ end
202
+
203
+
204
+ task :clean do
205
+ Dir[File.join(This.pkgdir, '**/**')].each{|entry| Fu.rm_rf(entry)}
206
+ end
207
+
208
+
209
+ task :release => [:clean, :gemspec, :gem] do
210
+ gems = Dir[File.join(This.pkgdir, '*.gem')].flatten
211
+ raise "which one? : #{ gems.inspect }" if gems.size > 1
212
+ raise "no gems?" if gems.size < 1
213
+
214
+ cmd = "gem push #{ This.gem }"
215
+ puts cmd
216
+ puts
217
+ system(cmd)
218
+ abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
219
+
220
+ cmd = "rubyforge login && rubyforge add_release #{ This.rubyforge_project } #{ This.lib } #{ This.version } #{ This.gem }"
221
+ puts cmd
222
+ puts
223
+ system(cmd)
224
+ abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
225
+ end
226
+
227
+
228
+
229
+
230
+
231
+ BEGIN {
232
+ # support for this rakefile
233
+ #
234
+ $VERBOSE = nil
235
+
236
+ require 'ostruct'
237
+ require 'erb'
238
+ require 'fileutils'
239
+ require 'rbconfig'
240
+ require 'pp'
241
+
242
+ # fu shortcut
243
+ #
244
+ Fu = FileUtils
245
+
246
+ # cache a bunch of stuff about this rakefile/environment
247
+ #
248
+ This = OpenStruct.new
249
+
250
+ This.file = File.expand_path(__FILE__)
251
+ This.dir = File.dirname(This.file)
252
+ This.pkgdir = File.join(This.dir, 'pkg')
253
+
254
+ # grok lib
255
+ #
256
+ lib = ENV['LIB']
257
+ unless lib
258
+ lib = File.basename(Dir.pwd).sub(/[-].*$/, '')
259
+ end
260
+ This.lib = lib
261
+
262
+ # grok version
263
+ #
264
+ version = ENV['VERSION']
265
+ unless version
266
+ require "./lib/#{ This.lib }"
267
+ This.name = lib.capitalize
268
+ This.object = eval(This.name)
269
+ version = This.object.send(:version)
270
+ end
271
+ This.version = version
272
+
273
+ # we need to know the name of the lib an it's version
274
+ #
275
+ abort('no lib') unless This.lib
276
+ abort('no version') unless This.version
277
+
278
+ # discover full path to this ruby executable
279
+ #
280
+ c = Config::CONFIG
281
+ bindir = c["bindir"] || c['BINDIR']
282
+ ruby_install_name = c['ruby_install_name'] || c['RUBY_INSTALL_NAME'] || 'ruby'
283
+ ruby_ext = c['EXEEXT'] || ''
284
+ ruby = File.join(bindir, (ruby_install_name + ruby_ext))
285
+ This.ruby = ruby
286
+
287
+ # some utils
288
+ #
289
+ module Util
290
+ def indent(s, n = 2)
291
+ s = unindent(s)
292
+ ws = ' ' * n
293
+ s.gsub(%r/^/, ws)
294
+ end
295
+
296
+ def unindent(s)
297
+ indent = nil
298
+ s.each_line do |line|
299
+ next if line =~ %r/^\s*$/
300
+ indent = line[%r/^\s*/] and break
301
+ end
302
+ indent ? s.gsub(%r/^#{ indent }/, "") : s
303
+ end
304
+ extend self
305
+ end
306
+
307
+ # template support
308
+ #
309
+ class Template
310
+ def initialize(&block)
311
+ @block = block
312
+ @template = block.call.to_s
313
+ end
314
+ def expand(b=nil)
315
+ ERB.new(Util.unindent(@template)).result((b||@block).binding)
316
+ end
317
+ alias_method 'to_s', 'expand'
318
+ end
319
+ def Template(*args, &block) Template.new(*args, &block) end
320
+
321
+ # colored console output support
322
+ #
323
+ This.ansi = {
324
+ :clear => "\e[0m",
325
+ :reset => "\e[0m",
326
+ :erase_line => "\e[K",
327
+ :erase_char => "\e[P",
328
+ :bold => "\e[1m",
329
+ :dark => "\e[2m",
330
+ :underline => "\e[4m",
331
+ :underscore => "\e[4m",
332
+ :blink => "\e[5m",
333
+ :reverse => "\e[7m",
334
+ :concealed => "\e[8m",
335
+ :black => "\e[30m",
336
+ :red => "\e[31m",
337
+ :green => "\e[32m",
338
+ :yellow => "\e[33m",
339
+ :blue => "\e[34m",
340
+ :magenta => "\e[35m",
341
+ :cyan => "\e[36m",
342
+ :white => "\e[37m",
343
+ :on_black => "\e[40m",
344
+ :on_red => "\e[41m",
345
+ :on_green => "\e[42m",
346
+ :on_yellow => "\e[43m",
347
+ :on_blue => "\e[44m",
348
+ :on_magenta => "\e[45m",
349
+ :on_cyan => "\e[46m",
350
+ :on_white => "\e[47m"
351
+ }
352
+ def say(phrase, *args)
353
+ options = args.last.is_a?(Hash) ? args.pop : {}
354
+ options[:color] = args.shift.to_s.to_sym unless args.empty?
355
+ keys = options.keys
356
+ keys.each{|key| options[key.to_s.to_sym] = options.delete(key)}
357
+
358
+ color = options[:color]
359
+ bold = options.has_key?(:bold)
360
+
361
+ parts = [phrase]
362
+ parts.unshift(This.ansi[color]) if color
363
+ parts.unshift(This.ansi[:bold]) if bold
364
+ parts.push(This.ansi[:clear]) if parts.size > 1
365
+
366
+ method = options[:method] || :puts
367
+
368
+ Kernel.send(method, parts.join)
369
+ end
370
+
371
+ # always run out of the project dir
372
+ #
373
+ Dir.chdir(This.dir)
374
+ }
@@ -0,0 +1,29 @@
1
+ ## ledis.gemspec
2
+ #
3
+
4
+ Gem::Specification::new do |spec|
5
+ spec.name = "ledis"
6
+ spec.version = "0.0.1"
7
+ spec.platform = Gem::Platform::RUBY
8
+ spec.summary = "ledis"
9
+ spec.description = "description: ledis kicks the ass"
10
+
11
+ spec.files =
12
+ ["README.md", "Rakefile", "ledis.gemspec", "lib", "lib/ledis.rb"]
13
+
14
+ spec.executables = []
15
+
16
+ spec.require_path = "lib"
17
+
18
+ spec.test_files = nil
19
+
20
+ ### spec.add_dependency 'lib', '>= version'
21
+ #### spec.add_dependency 'map'
22
+
23
+ spec.extensions.push(*[])
24
+
25
+ spec.rubyforge_project = "codeforpeople"
26
+ spec.author = "Ara T. Howard"
27
+ spec.email = "ara.t.howard@gmail.com"
28
+ spec.homepage = "https://github.com/ahoward/ledis"
29
+ end
@@ -0,0 +1,259 @@
1
+ # -*- encoding : utf-8 -*-
2
+ #
3
+ # NAME
4
+ #
5
+ # ledis
6
+ #
7
+ #
8
+ # SYNOPSIS
9
+ #
10
+ # a K.I.S.S auto-rotating redis logger for ruby/rails
11
+ #
12
+ # Ruby
13
+ #
14
+ # redis = Redis.new
15
+ #
16
+ # logger = Ledis.logger redis
17
+ #
18
+ # logger = Ledis.new
19
+ #
20
+ # logger = Ledis.new do |config|
21
+ #
22
+ # config.redis = Redis.new
23
+ #
24
+ # config.list = 'teh_foo:log'
25
+ #
26
+ # config.cap = 2 ** 16
27
+ #
28
+ # end
29
+ #
30
+ # Rails
31
+ #
32
+ # ### file: config/environments/development.rb
33
+ #
34
+ # config.logger = Ledis.logger do |logger|
35
+ #
36
+ # logger.list = "teh_rails_app:#{ Rails.env }:log"
37
+ #
38
+ # end
39
+ #
40
+ #
41
+ # DESCRIPTION
42
+ #
43
+ # ledis logs yo shiznit to redis. it's got built in logic to auto-truncate
44
+ # logs when they get to big
45
+ #
46
+ # logger.truncate(2 **16)
47
+ #
48
+ # and to grab the most recent ones
49
+ #
50
+ # puts logger.tail(1024)
51
+ #
52
+ # it's list/line oriented, just like a log file and makes no attempt to
53
+ # annotated log lines or add fancy data structures to them
54
+ #
55
+ # INSTALL
56
+ #
57
+ # gem 'ledis'
58
+ #
59
+
60
+ require 'logger'
61
+
62
+ module Ledis
63
+ ##
64
+ #
65
+ class << Ledis
66
+ def version
67
+ '0.0.1'
68
+ end
69
+
70
+ def dependencies
71
+ {
72
+ 'map' => [ 'map' , ' >= 6.0.1' ],
73
+ 'redis' => [ 'redis' , ' >= 2.2.2' ]
74
+ }
75
+ end
76
+ end
77
+
78
+ begin
79
+ require 'rubygems'
80
+ rescue LoadError
81
+ nil
82
+ end
83
+
84
+ dependencies.each do |lib, dependency|
85
+ gem(*dependency) if defined?(gem)
86
+ require(lib)
87
+ end
88
+
89
+ ##
90
+ #
91
+ class << Ledis
92
+ def logger(*args, &block)
93
+ return rails_logger(*args, &block) if defined?(::Rails.application)
94
+
95
+ Logger.new(*args, &block)
96
+ end
97
+
98
+ def rails_logger(*args, &block)
99
+ config = ::Rails.application.config
100
+
101
+ logger = Logger.new(*args, &block)
102
+
103
+ if defined?(::ActiveSupport::TaggedLogging)
104
+ logger = ::ActiveSupport::TaggedLogging.new(logger)
105
+ end
106
+
107
+ logger.level = config.log_level
108
+
109
+ logger
110
+ end
111
+ end
112
+
113
+ ##
114
+ #
115
+ class Logger < ::Logger
116
+ #
117
+ attr_accessor :logdev
118
+ attr_accessor :formatter
119
+
120
+ def initialize(*args, &block)
121
+ super(STDERR)
122
+ @logdev = LogDevice.new(*args, &block)
123
+ @formatter = Formatter.new
124
+ end
125
+
126
+ class Formatter < ::Logger::Formatter
127
+ Format = "%s, [%s#%d] %5s : %s\n"
128
+
129
+ def call(severity, time, progname, msg)
130
+ Format %
131
+ [severity[0..0], format_datetime(time), $$, severity, msg2str(msg)]
132
+ end
133
+ end
134
+
135
+ def << (*args)
136
+ super
137
+ self
138
+ end
139
+
140
+ def level=(level)
141
+ @level = level_for(level)
142
+ end
143
+
144
+ Levels =
145
+ Hash[ Severity.constants.map{|c| [c.to_s.downcase, Severity.const_get(c)]} ]
146
+
147
+ def level_for(level)
148
+ case level
149
+ when Integer
150
+ Levels[ Levels.invert[level] || 4 ]
151
+ else
152
+ Levels[ level.to_s.downcase ]
153
+ end
154
+ end
155
+
156
+ %w(
157
+ redis redis=
158
+ list list=
159
+ cap cap=
160
+ step step=
161
+ cycle cycle=
162
+ tail
163
+ truncate
164
+ size
165
+ ).each do |method|
166
+ case method
167
+ when /=/
168
+ class_eval <<-__, __FILE__, __LINE__
169
+ def #{ method }(arg)
170
+ @logdev.#{ method }(arg)
171
+ end
172
+ __
173
+
174
+ else
175
+ class_eval <<-__, __FILE__, __LINE__
176
+ def #{ method }(*args, &block)
177
+ @logdev.#{ method }(*args, &block)
178
+ end
179
+ __
180
+ end
181
+ end
182
+
183
+ ##
184
+ #
185
+ class LogDevice
186
+ attr_accessor :config
187
+ attr_accessor :cap
188
+ attr_accessor :step
189
+ attr_accessor :cycle
190
+ attr_accessor :list
191
+
192
+ def initialize(*args, &block)
193
+ config = Map.options_for!(args)
194
+ config[:redis] ||= args.shift
195
+ configure(config, &block)
196
+ end
197
+
198
+ def configure(config = {}, &block)
199
+ @config = Map.for(config)
200
+
201
+ block.call(@config) if block
202
+
203
+ @redis = @config[:redis] || @redis
204
+ @cap = @config[:cap] || (2 ** 16)
205
+ @step = @config[:step] || 0
206
+ @cycle = @config[:cycle] || (2 ** 8)
207
+ @list = @config[:list] || 'ledis:log'
208
+ end
209
+
210
+ def redis
211
+ @redis ||= Redis.new
212
+ end
213
+
214
+ def redis=(redis)
215
+ @redis = redis
216
+ end
217
+
218
+ def write(message)
219
+ begin
220
+ redis.lpush(list, message)
221
+ rescue Object => e
222
+ error = "#{ e.message } (#{ e.class })\n#{ Array(e.backtrace).join(10.chr) }"
223
+ STDERR.puts(error)
224
+ STDERR.puts(message)
225
+ end
226
+ ensure
227
+ if (@step % @cycle).zero?
228
+ truncate(@cap) rescue nil
229
+ end
230
+ @step = (@step + 1) % @cycle
231
+ end
232
+
233
+ if defined?(Rails::Server) and STDOUT.tty? and not defined?(ActiveSupport::Logger.broadcast)
234
+ alias_method('__write__', 'write')
235
+
236
+ def write(message, &block)
237
+ STDOUT.puts(message)
238
+ __write__(message, &block)
239
+ end
240
+ end
241
+
242
+ def close
243
+ redis.quit rescue nil
244
+ end
245
+
246
+ def tail(n = 1024)
247
+ redis.lrange(list, 0, n - 1).reverse
248
+ end
249
+
250
+ def truncate(size)
251
+ redis.ltrim(list, 0, size - 1)
252
+ end
253
+
254
+ def size
255
+ redis.llen(list)
256
+ end
257
+ end
258
+ end
259
+ end
metadata ADDED
@@ -0,0 +1,48 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ledis
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ara T. Howard
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-06-15 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: ! 'description: ledis kicks the ass'
15
+ email: ara.t.howard@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - README.md
21
+ - Rakefile
22
+ - ledis.gemspec
23
+ - lib/ledis.rb
24
+ homepage: https://github.com/ahoward/ledis
25
+ licenses: []
26
+ post_install_message:
27
+ rdoc_options: []
28
+ require_paths:
29
+ - lib
30
+ required_ruby_version: !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ! '>='
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ required_rubygems_version: !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ! '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ requirements: []
43
+ rubyforge_project: codeforpeople
44
+ rubygems_version: 1.8.23
45
+ signing_key:
46
+ specification_version: 3
47
+ summary: ledis
48
+ test_files: []