eventdb 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gemtest +0 -0
- data/Manifest.txt +15 -0
- data/README.md +29 -10
- data/Rakefile +0 -2
- data/bin/rubyconf +17 -0
- data/lib/eventdb/calendar.rb +73 -0
- data/lib/eventdb/database.rb +46 -0
- data/lib/eventdb/models.rb +12 -0
- data/lib/eventdb/reader.rb +178 -0
- data/lib/eventdb/rubyconf.rb +40 -0
- data/lib/eventdb/schema.rb +24 -0
- data/lib/eventdb/version.rb +2 -2
- data/lib/eventdb.rb +23 -0
- data/templates/CALENDAR.md.erb +24 -0
- data/test/data/RUBY.md +647 -0
- data/test/helper.rb +8 -0
- data/test/test_calendar.rb +50 -0
- data/test/test_database.rb +37 -0
- data/test/test_reader.rb +26 -0
- data/test/test_rubyconf.rb +21 -0
- data/test/test_version.rb +18 -0
- metadata +25 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 64679b23d00fead03540ef38cdabb5c89a5a21e2
|
4
|
+
data.tar.gz: 6ad469e6a30aadc53fc0fe9588523a5b3ee76a91
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a24433d3494b0ca8f33f9026a16935f37926d6fa41c90296769f5fadca446c2751ed0673b9d5b9a541ab00ad83f369ef0348af9bedbf5dd089c9db1ded0f111
|
7
|
+
data.tar.gz: 5b20c163139483092d455bfe4364fc57e50e16c3c60ee7252225b81017be99bfe521483065c1defa721e904abb15d57c1327f43e3c100d7115e5c06df2cbc51d
|
data/.gemtest
ADDED
File without changes
|
data/Manifest.txt
CHANGED
@@ -2,5 +2,20 @@ HISTORY.md
|
|
2
2
|
Manifest.txt
|
3
3
|
README.md
|
4
4
|
Rakefile
|
5
|
+
bin/rubyconf
|
5
6
|
lib/eventdb.rb
|
7
|
+
lib/eventdb/calendar.rb
|
8
|
+
lib/eventdb/database.rb
|
9
|
+
lib/eventdb/models.rb
|
10
|
+
lib/eventdb/reader.rb
|
11
|
+
lib/eventdb/rubyconf.rb
|
12
|
+
lib/eventdb/schema.rb
|
6
13
|
lib/eventdb/version.rb
|
14
|
+
templates/CALENDAR.md.erb
|
15
|
+
test/data/RUBY.md
|
16
|
+
test/helper.rb
|
17
|
+
test/test_calendar.rb
|
18
|
+
test/test_database.rb
|
19
|
+
test/test_reader.rb
|
20
|
+
test/test_rubyconf.rb
|
21
|
+
test/test_version.rb
|
data/README.md
CHANGED
@@ -6,7 +6,7 @@ event.db models n tools
|
|
6
6
|
* bugs :: [github.com/textkit/event.db/issues](https://github.com/textkit/event.db/issues)
|
7
7
|
* gem :: [rubygems.org/gems/eventdb](https://rubygems.org/gems/eventdb)
|
8
8
|
* rdoc :: [rubydoc.info/gems/eventdb](http://rubydoc.info/gems/eventdb)
|
9
|
-
* forum :: [ruby-talk@ruby-lang.org](www.ruby-lang.org/en/community/mailing-lists)
|
9
|
+
* forum :: [ruby-talk@ruby-lang.org](http://www.ruby-lang.org/en/community/mailing-lists)
|
10
10
|
|
11
11
|
|
12
12
|
## Command-Line Tool Usage
|
@@ -18,15 +18,34 @@ The eventdb gem includes command-line tools to list upcoming events.
|
|
18
18
|
|
19
19
|
Use
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
21
|
+
~~~
|
22
|
+
$ rubyconf
|
23
|
+
~~~
|
24
|
+
|
25
|
+
to list the upcoming Ruby conferences from around the world. Will print:
|
26
|
+
|
27
|
+
~~~
|
28
|
+
Upcoming Ruby Conferences:
|
29
|
+
|
30
|
+
Jul/1+2 - RubyMotion Conference - #inspect @ Paris, France › Europe
|
31
|
+
Jul/20 - Brighton Ruby Conference @ Brighton, East Sussex › England (en) › Western Europe › Europe
|
32
|
+
Jul/31-Aug/2 - European Ruby Camp - eurucamp @ Berlin (Potsdam), Germany › Europe
|
33
|
+
Jul/31 - JRuby Conference Europe - JRubyConf EU @ Berlin (Potdam), Germany › Europe
|
34
|
+
Aug/1+2 - Burlington Ruby Conference @ Burlington, Vermont › New England › United States (us) › North America › America
|
35
|
+
Aug/21+22 - Madison+ Ruby @ Madison, Wisconsin › Great Lakes › United States (us) › North America › America
|
36
|
+
Sept/1–5 - Full Stack Fest - Barcelona Ruby Conference (BaRuCo) + Barcelona Future JS @ Barcelona, Catalonia › Spain / España (es) › Southern Europe › Europe
|
37
|
+
Sept/11+12 - RubyConf Taiwan @ Taipei › Taiwan (tw) › Asia
|
38
|
+
Sep/14+15 - RubyConf Portugal @ Braga › Portugal (pt) › Southern Europe › Europe
|
39
|
+
Sept/18+19 - RubyConf Brasil @ São Paulo › Brazil / Brasil (br) › South America › America
|
40
|
+
Sept/23-25 - Rocky Mountain Ruby Conference @ Boulder, Colorado › Rocky Mountains › United States (us) › North America › America
|
41
|
+
Sept/26 - Ruby Open Source Software (ROSS) Conference - ROSSConf @ Berlin, Germany › Europe
|
42
|
+
Oct/1+2 - ArrrCamp @ Ghent, Oost-Vlaanderen › Belgium / België / Belgique (be) › Western Europe › Europe
|
43
|
+
Oct/15+16 - RubyConf Colombia @ Medellin › Colombia (co) › South America › America
|
44
|
+
Oct/17+18 - European Ruby Konference - EuRuKo @ Salzburg, Austria › Europe
|
45
|
+
Nov/11+12 - RubyWorld Conference @ Matsue › Japan (jp) › Asia
|
46
|
+
|
47
|
+
More @ github.com/planetruby/awesome-events
|
48
|
+
~~~
|
30
49
|
|
31
50
|
|
32
51
|
|
data/Rakefile
CHANGED
data/bin/rubyconf
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
###################
|
4
|
+
# == DEV TIPS:
|
5
|
+
#
|
6
|
+
# For local testing run like:
|
7
|
+
#
|
8
|
+
# ruby -Ilib bin/rubyconf
|
9
|
+
#
|
10
|
+
# Set the executable bit in Linux. Example:
|
11
|
+
#
|
12
|
+
# % chmod a+x bin/rubyconf
|
13
|
+
#
|
14
|
+
|
15
|
+
require 'eventdb'
|
16
|
+
|
17
|
+
EventDb::RubyConf.new.print
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module EventDb
|
4
|
+
|
5
|
+
class EventCursor
|
6
|
+
def initialize( events )
|
7
|
+
@events = events
|
8
|
+
end
|
9
|
+
|
10
|
+
def each
|
11
|
+
state = State.new
|
12
|
+
@events.each do |event|
|
13
|
+
state.next( event )
|
14
|
+
yield( event, state )
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class State
|
19
|
+
def initialize
|
20
|
+
@last_date = Date.new( 1971, 1, 1 )
|
21
|
+
@new_date = true
|
22
|
+
@new_year = true
|
23
|
+
@new_month = true
|
24
|
+
end
|
25
|
+
def new_date?() @new_date; end
|
26
|
+
def new_year?() @new_year; end
|
27
|
+
def new_month?() @new_month; end
|
28
|
+
|
29
|
+
def next( event )
|
30
|
+
if @last_date.year == event.start_date.year &&
|
31
|
+
@last_date.month == event.start_date.month
|
32
|
+
@new_date = false
|
33
|
+
@new_year = false
|
34
|
+
@new_month = false
|
35
|
+
else
|
36
|
+
@new_date = true
|
37
|
+
## new year?
|
38
|
+
@new_year = @last_date.year != event.start_date.year ? true : false
|
39
|
+
## new_month ?
|
40
|
+
@new_month = (@new_year == true || @last_date.month != event.start_date.month) ? true : false
|
41
|
+
end
|
42
|
+
@last_date = event.start_date
|
43
|
+
end
|
44
|
+
|
45
|
+
end # class State
|
46
|
+
|
47
|
+
end # class EventCursor
|
48
|
+
|
49
|
+
|
50
|
+
class EventCalendar
|
51
|
+
|
52
|
+
def initialize( events )
|
53
|
+
@events = events.sort { |l,r| r.start_date <=> l.start_date } ## sort events by date (newest first)
|
54
|
+
@tmpl = File.read_utf8( "#{EventDb.root}/templates/CALENDAR.md.erb" )
|
55
|
+
end
|
56
|
+
|
57
|
+
def events
|
58
|
+
## note: return new cursor -- use decorator (instead of extra loop arg, why? why not?
|
59
|
+
EventCursor.new( @events )
|
60
|
+
end
|
61
|
+
|
62
|
+
def render
|
63
|
+
ERB.new( @tmpl, nil, '<>' ).result( binding ) # <> omit newline for lines starting with <% and ending in %>
|
64
|
+
end
|
65
|
+
|
66
|
+
def save( path = './CALENDAR.md' ) ## use (rename to) save_as - why? why not??
|
67
|
+
File.open( path, 'w' ) do |f|
|
68
|
+
f.write( render )
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end # class EventCalendar
|
72
|
+
|
73
|
+
end # module EventDb
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module EventDb
|
4
|
+
|
5
|
+
class Database
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
## connect
|
9
|
+
|
10
|
+
ActiveRecord::Base.establish_connection( adapter: 'sqlite3',
|
11
|
+
database: ':memory:' )
|
12
|
+
|
13
|
+
LogDb.create # add logs table
|
14
|
+
ConfDb.create
|
15
|
+
|
16
|
+
CreateDb.new.up
|
17
|
+
ConfDb::Model::Prop.create!( key: 'db.schema.event.version', value: VERSION )
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def add( events )
|
22
|
+
events.each do |ev|
|
23
|
+
|
24
|
+
## note: extract title from first (markdown) link
|
25
|
+
m = (ev.title =~ /^\[([^\]]+)\]/)
|
26
|
+
if m
|
27
|
+
title = $1
|
28
|
+
puts " adding #{title} #{ev.start_date.year}, #{ev.date}"
|
29
|
+
else
|
30
|
+
puts "warn: cannot find event title in #{ev.title}"
|
31
|
+
next # skip record; todo: issue error
|
32
|
+
end
|
33
|
+
|
34
|
+
Model::Event.create!(
|
35
|
+
title: title,
|
36
|
+
place: ev.place,
|
37
|
+
date: ev.date,
|
38
|
+
start_date: ev.start_date
|
39
|
+
)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end # class Database
|
44
|
+
|
45
|
+
end # module EventDb
|
46
|
+
|
@@ -0,0 +1,178 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
|
4
|
+
module EventDb
|
5
|
+
|
6
|
+
|
7
|
+
class EventReader
|
8
|
+
|
9
|
+
include LogUtils::Logging
|
10
|
+
|
11
|
+
|
12
|
+
Event = Struct.new( :title, :place, :date, :start_date)
|
13
|
+
|
14
|
+
def self.from_url( src ) # note: src assumed a string
|
15
|
+
worker = Fetcher::Worker.new
|
16
|
+
self.from_string( worker.read_utf8!( src ) )
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.from_file( path )
|
20
|
+
self.from_string( File.read_utf8( path ) )
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.from_string( text )
|
24
|
+
self.new( text )
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def initialize( text )
|
29
|
+
@text = text
|
30
|
+
end
|
31
|
+
|
32
|
+
MONTH_EN_TO_MM = {
|
33
|
+
'Jan' => '1',
|
34
|
+
'Feb' => '2',
|
35
|
+
'Mar' => '3', 'March' => '3',
|
36
|
+
'Apr' => '4', 'April' => '4',
|
37
|
+
'May' => '5',
|
38
|
+
'Jun' => '6', 'June' => '6',
|
39
|
+
'Jul' => '7', 'July' => '7',
|
40
|
+
'Aug' => '8',
|
41
|
+
'Sep' => '9', 'Sept' => '9',
|
42
|
+
'Oct' => '10',
|
43
|
+
'Nov' => '11',
|
44
|
+
'Dec' => '12' }
|
45
|
+
|
46
|
+
MONTH_EN = MONTH_EN_TO_MM.keys.join('|') # e.g. 'Jan|Feb|March|Mar|...'
|
47
|
+
|
48
|
+
## examples:
|
49
|
+
## - 2015 @ Salzburg, Austria; Oct/17+18
|
50
|
+
## - 2015 @ Brussels / Brussel / Bruxelles; Jan/31+Feb/1
|
51
|
+
## - 2014 @ Porto de Galinhas, Pernambuco; Apr/24-27 (formerly: Abril Pro Ruby)
|
52
|
+
|
53
|
+
DATE_ENTRY_REGEX = /\s+
|
54
|
+
(?<year>201\d) ## year
|
55
|
+
\s+
|
56
|
+
@ ## at location
|
57
|
+
\s+
|
58
|
+
[^;]+ ## use ; as separator between place and date
|
59
|
+
;
|
60
|
+
\s+
|
61
|
+
(?<month_en>#{MONTH_EN})
|
62
|
+
\/
|
63
|
+
(?<day>[0-9]{1,2}) ## start date
|
64
|
+
/x
|
65
|
+
|
66
|
+
|
67
|
+
## example:
|
68
|
+
## - [RubyWorld Conference - rubyworldconf](http://www.rubyworld-conf.org/en)
|
69
|
+
|
70
|
+
LINK_ENTRY_REGEX = /\s+
|
71
|
+
\[
|
72
|
+
[^\]]+
|
73
|
+
\]
|
74
|
+
\(
|
75
|
+
[^\)]+
|
76
|
+
\)
|
77
|
+
/x
|
78
|
+
|
79
|
+
|
80
|
+
def read
|
81
|
+
|
82
|
+
events = []
|
83
|
+
stack = [] ## header/heading stack; note: last_stack is stack.size; starts w/ 0
|
84
|
+
|
85
|
+
last_link_entry = nil
|
86
|
+
|
87
|
+
@text.each_line do |line|
|
88
|
+
|
89
|
+
logger.debug "line: >#{line}<"
|
90
|
+
line = line.rstrip ## remove (possible) trailing newline
|
91
|
+
|
92
|
+
break if line =~ /^## More/ # stop when hitting >## More< section
|
93
|
+
next if line =~ /^\s*$/ # skip blank lines
|
94
|
+
|
95
|
+
m = nil
|
96
|
+
if line =~ /^[ ]*(#+)[ ]+/ ## heading/headers - note: must escpape #
|
97
|
+
s = StringScanner.new( line )
|
98
|
+
s.skip( /[ ]*/ ) ## skip whitespaces
|
99
|
+
markers = s.scan( /#+/)
|
100
|
+
level = markers.size
|
101
|
+
s.skip( /[ ]*/ ) ## skip whitespaces
|
102
|
+
title = s.rest.rstrip
|
103
|
+
|
104
|
+
logger.debug " heading level: #{level}, title: >#{title}<"
|
105
|
+
|
106
|
+
level_diff = level - stack.size
|
107
|
+
|
108
|
+
if level_diff > 0
|
109
|
+
logger.debug "[EventReader] up +#{level_diff}"
|
110
|
+
if level_diff > 1
|
111
|
+
logger.error "fatal: level step must be one (+1) is +#{level_diff}"
|
112
|
+
fail "[EventReader] level step must be one (+1) is +#{level_diff}"
|
113
|
+
end
|
114
|
+
elsif level_diff < 0
|
115
|
+
logger.debug "[EventReader] down #{level_diff}"
|
116
|
+
level_diff.abs.times { stack.pop }
|
117
|
+
stack.pop
|
118
|
+
else
|
119
|
+
## same level
|
120
|
+
stack.pop
|
121
|
+
end
|
122
|
+
stack.push( [level,title] )
|
123
|
+
logger.debug " stack: #{stack.inspect}"
|
124
|
+
|
125
|
+
elsif line =~ /^[ ]*-[ ]+/ ## list item
|
126
|
+
if( m=LINK_ENTRY_REGEX.match( line ) )
|
127
|
+
logger.debug " link entry: #{line}"
|
128
|
+
|
129
|
+
s = StringScanner.new( line )
|
130
|
+
s.skip( /[ ]*-[ ]*/ ) ## skip leading list
|
131
|
+
last_link_entry = s.rest.rstrip ## remove trailing spaces to
|
132
|
+
elsif( m=DATE_ENTRY_REGEX.match( line ) )
|
133
|
+
year = m[:year]
|
134
|
+
month_en = m[:month_en]
|
135
|
+
month = MONTH_EN_TO_MM[ month_en ]
|
136
|
+
day = m[:day]
|
137
|
+
start_date = Date.new( year.to_i, month.to_i, day.to_i )
|
138
|
+
## pp start_date
|
139
|
+
|
140
|
+
logger.debug " date entry: #{line}"
|
141
|
+
logger.debug " start_date: #{start_date}, year: #{year}, month_en: #{month_en}, month: #{month} day: #{day} => #{last_link_entry}"
|
142
|
+
|
143
|
+
s = StringScanner.new( line )
|
144
|
+
s.skip( /[ ]*-[ ]*/ ) ## skip leading list
|
145
|
+
s.skip_until( /@/ )
|
146
|
+
|
147
|
+
place = s.scan( /[^;]+/ ) ## get place (everything until ; (separator))
|
148
|
+
place = place.strip
|
149
|
+
logger.debug " place: #{place}, rest: >#{s.rest}<"
|
150
|
+
|
151
|
+
## note: cut of heading 1 (e.g. awesome-events title)
|
152
|
+
more_places = stack[1..-1].reverse.map {|it| it[1] }.join(' › ')
|
153
|
+
place = "#{place} › #{more_places}"
|
154
|
+
logger.debug " place: #{place}"
|
155
|
+
|
156
|
+
s.skip( /;/ )
|
157
|
+
s.skip( /[ ]*/ ) ## skip whitespaces
|
158
|
+
date = s.scan( /[^ ]+/ ) # e.g. everything untils first space (or end-of-line)
|
159
|
+
|
160
|
+
title = last_link_entry
|
161
|
+
|
162
|
+
event = Event.new( title, place, date, start_date )
|
163
|
+
## pp event
|
164
|
+
events << event
|
165
|
+
else
|
166
|
+
logger.debug " *** skip list item line: #{line}"
|
167
|
+
end
|
168
|
+
else
|
169
|
+
logger.debug " *** skip line: #{line}"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
events
|
174
|
+
end
|
175
|
+
|
176
|
+
end # class EventReader
|
177
|
+
|
178
|
+
end # module EventDb
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module EventDb
|
4
|
+
|
5
|
+
class RubyConf
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
## turn down logger (default :debug?)
|
9
|
+
LogUtils::Logger.root.level = :info
|
10
|
+
|
11
|
+
r = EventDb::EventReader.from_url( "https://github.com/planetruby/awesome-events/raw/master/README.md" )
|
12
|
+
events = r.read
|
13
|
+
|
14
|
+
@db = EventDb::Database.new
|
15
|
+
@db.add( events )
|
16
|
+
end
|
17
|
+
|
18
|
+
def print
|
19
|
+
## get next 17 events
|
20
|
+
up = EventDb::Model::Event.limit( 17 )
|
21
|
+
.order( 'start_date' )
|
22
|
+
.where( 'start_date >= ?', Date.today )
|
23
|
+
## pp up.to_sql
|
24
|
+
## pp up
|
25
|
+
|
26
|
+
puts ''
|
27
|
+
puts ''
|
28
|
+
puts "Upcoming Ruby Conferences:"
|
29
|
+
puts ''
|
30
|
+
up.each do |e|
|
31
|
+
puts " #{e.date} - #{e.title} @ #{e.place}"
|
32
|
+
end
|
33
|
+
puts ''
|
34
|
+
puts " More @ github.com/planetruby/awesome-events"
|
35
|
+
puts ''
|
36
|
+
end
|
37
|
+
|
38
|
+
end # class RubyConf
|
39
|
+
|
40
|
+
end # module EventDb
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module EventDb
|
4
|
+
|
5
|
+
class CreateDb
|
6
|
+
|
7
|
+
def up
|
8
|
+
ActiveRecord::Schema.define do
|
9
|
+
|
10
|
+
create_table :events do |t|
|
11
|
+
t.string :title, null: false
|
12
|
+
t.string :place, null: false
|
13
|
+
t.string :date, null: false # note: full date range (start to end) for now as *string*
|
14
|
+
t.date :start_date, null: false ## use (rename) to start_at - why? why not?
|
15
|
+
|
16
|
+
t.timestamps
|
17
|
+
end
|
18
|
+
|
19
|
+
end # Schema.define
|
20
|
+
end # method up
|
21
|
+
|
22
|
+
end # class CreateDb
|
23
|
+
|
24
|
+
end # module EventDb
|
data/lib/eventdb/version.rb
CHANGED
data/lib/eventdb.rb
CHANGED
@@ -1,10 +1,33 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
+
# stdlibs
|
4
|
+
require 'pp'
|
5
|
+
require 'date'
|
6
|
+
require 'strscan' ## StringScanner lib
|
7
|
+
require 'erb'
|
8
|
+
|
9
|
+
# 3rd party libs (gems)
|
10
|
+
require 'props'
|
11
|
+
require 'logutils'
|
12
|
+
require 'textutils'
|
13
|
+
require 'props/activerecord'
|
14
|
+
require 'logutils/activerecord'
|
15
|
+
require 'fetcher'
|
3
16
|
|
4
17
|
# our own code
|
5
18
|
|
6
19
|
require 'eventdb/version' ## let version always go first
|
7
20
|
|
21
|
+
require 'eventdb/schema'
|
22
|
+
require 'eventdb/reader'
|
23
|
+
require 'eventdb/calendar'
|
24
|
+
|
25
|
+
require 'eventdb/models'
|
26
|
+
require 'eventdb/database'
|
27
|
+
|
28
|
+
require 'eventdb/rubyconf'
|
29
|
+
|
30
|
+
|
8
31
|
|
9
32
|
|
10
33
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Ruby Conference Calendar
|
2
|
+
|
3
|
+
NOTE: This page gets auto-generated from the [awesome-events](README.md) page @ Planet Ruby.
|
4
|
+
(Last update on <%= Date.today %>.) Do NOT edit this page, please update or edit conferences, camps, meetups etc.
|
5
|
+
on the [awesome-events](README.md) page. Anything missing? Contributions welcome. Thanks!
|
6
|
+
|
7
|
+
|
8
|
+
[2016](#2016) • [2015](#2015) • [2014](#2014) • [2013](#2013)
|
9
|
+
|
10
|
+
<% events.each do |ev,evd| %>
|
11
|
+
<% if evd.new_year? %>
|
12
|
+
|
13
|
+
## <%= ev.start_date.year %>
|
14
|
+
|
15
|
+
<% end %>
|
16
|
+
<% if evd.new_month? %>
|
17
|
+
|
18
|
+
**<%= Date::MONTHNAMES[ev.start_date.month] %>**
|
19
|
+
|
20
|
+
<% end %>
|
21
|
+
|
22
|
+
<%= ev.date %> • **<%= ev.title %>** @ <%= ev.place %>
|
23
|
+
|
24
|
+
<% end %>
|