meetup-generator 0.0.20210128 → 1.2.84
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +5 -0
- data/.travis.yml +17 -0
- data/Gemfile +1 -3
- data/README.md +6 -50
- data/Rakefile +11 -4
- data/bin/meetup-generator.rb +14 -17
- data/config.ru +0 -2
- data/lib/all_the_things.yaml +126 -436
- data/lib/build_helpers.rb +9 -0
- data/lib/meetup-generator.rb +63 -0
- data/lib/version.rb +4 -0
- data/meetup-generator.gemspec +16 -24
- data/public/css/main.css +2 -5
- data/spec/acceptance_spec.rb +33 -62
- data/spec/unit_spec.rb +68 -0
- data/views/default.slim +14 -14
- data/{package/meetup-generator.xml → website.xml} +2 -2
- metadata +82 -78
- data/Gemfile.lock +0 -84
- data/bin/locate_meetup-generator +0 -6
- data/lib/locator.rb +0 -7
- data/lib/meetup_generator.rb +0 -106
- data/lib/words.gz +0 -0
- data/spec/meetup_generator_spec.rb +0 -138
- data/views/partial_talk.slim +0 -11
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
# Everything needed for a meetup generator
|
5
|
+
#
|
6
|
+
class MeetupGenerator
|
7
|
+
attr_reader :words, :lib, :unused_templates
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
grep, dict = find_unix_stuff
|
11
|
+
@words = `#{grep} "^[a-z]*$" #{dict}`.split("\n")
|
12
|
+
@lib = YAML.load_file(ROOT + 'lib' + 'all_the_things.yaml')
|
13
|
+
end
|
14
|
+
|
15
|
+
def find_unix_stuff
|
16
|
+
case RUBY_PLATFORM
|
17
|
+
when /solaris/
|
18
|
+
%w[/bin/grep /usr/share/lib/dict/words]
|
19
|
+
when /linux/
|
20
|
+
%w[/bin/grep /usr/share/dict/words]
|
21
|
+
when /darwin/
|
22
|
+
%w[/usr/bin/grep /usr/share/dict/words]
|
23
|
+
else
|
24
|
+
abort "unsupported platform: #{RUBY_PLATFORM}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def title
|
29
|
+
@unused_templates ||= lib[:template].dup
|
30
|
+
t = unused_templates.sample
|
31
|
+
unused_templates.delete(t)
|
32
|
+
t.scan(/%\w+%/).each { |k| t = t.sub(k, lib[k[1..-2].to_sym].sample) }
|
33
|
+
t.scan(/RAND\d+/).each do |i|
|
34
|
+
t = t.sub(i, rand(2..(i.sub(/RAND/, '').to_i)).to_s)
|
35
|
+
end
|
36
|
+
t
|
37
|
+
end
|
38
|
+
|
39
|
+
def talks(count = 5)
|
40
|
+
@unused_templates = lib[:template].dup
|
41
|
+
count.times.with_object([]) { |_i, a| a.<< title }
|
42
|
+
end
|
43
|
+
|
44
|
+
def talker
|
45
|
+
lib[:first_name].sample + ' ' + lib[:last_name].sample
|
46
|
+
end
|
47
|
+
|
48
|
+
def role
|
49
|
+
lib[:job_role].sample + ' ' + lib[:job_title].sample
|
50
|
+
end
|
51
|
+
|
52
|
+
def company
|
53
|
+
words.sample.sub(/([^aeiou])er$/, '\\1r').downcase + '.io'
|
54
|
+
end
|
55
|
+
|
56
|
+
def refreshment
|
57
|
+
lib[:food_style].sample + ' ' + lib[:food].sample
|
58
|
+
end
|
59
|
+
|
60
|
+
def talk
|
61
|
+
{ talk: talks(1)[0], talker: talker, role: role, company: company }
|
62
|
+
end
|
63
|
+
end
|
data/lib/version.rb
ADDED
data/meetup-generator.gemspec
CHANGED
@@ -1,13 +1,11 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require 'pathname'
|
3
2
|
require 'date'
|
4
|
-
|
5
|
-
|
3
|
+
require 'English'
|
4
|
+
require_relative 'lib/build_helpers'
|
6
5
|
|
7
6
|
Gem::Specification.new do |gem|
|
8
7
|
gem.name = 'meetup-generator'
|
9
|
-
gem.version =
|
10
|
-
"0.0.#{Time.now.strftime('%Y%m%d')}"
|
8
|
+
gem.version = gem_version
|
11
9
|
gem.date = Date.today.to_s
|
12
10
|
|
13
11
|
gem.summary = 'Stupid fatuous random string generatpr'
|
@@ -15,29 +13,23 @@ Gem::Specification.new do |gem|
|
|
15
13
|
'DevOps meetup, using all the latest buzzwords, ' \
|
16
14
|
'new-shiny, and clichés'
|
17
15
|
gem.authors = ['Robert Fisher']
|
18
|
-
gem.email = '
|
16
|
+
gem.email = 'slackboy@gmail.com'
|
19
17
|
gem.homepage = 'https://github.com/snltd/meetup-generator'
|
20
18
|
gem.license = 'BSD-2-Clause'
|
21
19
|
|
22
|
-
gem.
|
23
|
-
gem.executables = ['meetup-generator.rb', 'locate_meetup-generator']
|
24
|
-
gem.files = IO.readlines('package/runtime_files', chomp: true)
|
20
|
+
gem.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
25
21
|
gem.test_files = gem.files.grep(%r{^spec/})
|
26
|
-
gem.require_paths = %w[lib]
|
27
22
|
|
28
|
-
gem.add_runtime_dependency '
|
29
|
-
gem.add_runtime_dependency '
|
30
|
-
gem.add_runtime_dependency '
|
23
|
+
gem.add_runtime_dependency 'sinatra', '~>2.0', '>= 2.0.1'
|
24
|
+
gem.add_runtime_dependency 'slim', '~> 3.0', '>= 3.0.0'
|
25
|
+
gem.add_runtime_dependency 'puma', '~> 3.11', '>= 3.11.0'
|
31
26
|
|
32
|
-
gem.add_development_dependency 'bundler', '~>
|
33
|
-
gem.add_development_dependency 'minitest', '~> 5.
|
34
|
-
gem.add_development_dependency 'nokogiri', '~> 1.
|
35
|
-
gem.add_development_dependency 'rack-test', '~>
|
36
|
-
gem.add_development_dependency 'rake', '~>
|
37
|
-
gem.add_development_dependency 'rubocop', '~>
|
38
|
-
gem.add_development_dependency 'rubocop-minitest', '~> 0.10'
|
39
|
-
gem.add_development_dependency 'rubocop-performance', '~> 1.3'
|
40
|
-
gem.add_development_dependency 'rubocop-rake', '~> 0.5'
|
27
|
+
gem.add_development_dependency 'bundler', '~> 1.3'
|
28
|
+
gem.add_development_dependency 'minitest', '~> 5.11', '>= 5.11.0'
|
29
|
+
gem.add_development_dependency 'nokogiri', '~> 1.8', '>= 1.8.0'
|
30
|
+
gem.add_development_dependency 'rack-test', '~> 0.8', '>= 0.8.0'
|
31
|
+
gem.add_development_dependency 'rake', '~> 12.3', '>= 12.3.0'
|
32
|
+
gem.add_development_dependency 'rubocop', '~> 0.52', '>= 0.52.0'
|
41
33
|
|
42
|
-
gem.required_ruby_version = Gem::Requirement.new('>= 2.
|
34
|
+
gem.required_ruby_version = Gem::Requirement.new('>= 2.2.0')
|
43
35
|
end
|
data/public/css/main.css
CHANGED
@@ -11,15 +11,11 @@ body {
|
|
11
11
|
line-height: 120%;
|
12
12
|
}
|
13
13
|
|
14
|
-
.
|
14
|
+
.tperson {
|
15
15
|
font-size: small;
|
16
16
|
margin-left: 12em;
|
17
17
|
}
|
18
18
|
|
19
|
-
.indent a {
|
20
|
-
color: #0f0;
|
21
|
-
}
|
22
|
-
|
23
19
|
ul {
|
24
20
|
list-style: none;
|
25
21
|
}
|
@@ -31,6 +27,7 @@ li {
|
|
31
27
|
}
|
32
28
|
|
33
29
|
.ttitle {
|
30
|
+
/*font-style: italic;*/
|
34
31
|
font-weight: bold;
|
35
32
|
background-color: #0ff;
|
36
33
|
color: #000;
|
data/spec/acceptance_spec.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
#
|
3
|
-
|
2
|
+
#
|
3
|
+
# Acceptance tests for the meetup generator. Yeah, I know.
|
4
|
+
#
|
4
5
|
%w[minitest minitest/unit minitest/autorun rack/test pathname json
|
5
6
|
yaml cgi nokogiri].each { |f| require f }
|
6
7
|
|
@@ -8,25 +9,21 @@ MGROOT = Pathname.new(__FILE__).realpath.dirname.parent
|
|
8
9
|
|
9
10
|
OUTER_APP = Rack::Builder.parse_file((MGROOT + 'config.ru').to_s).first
|
10
11
|
|
11
|
-
# Acceptance tests for the meetup generator. Yeah, I know.
|
12
|
-
#
|
13
12
|
class TestApp < MiniTest::Test
|
14
13
|
attr_reader :things
|
15
|
-
|
16
14
|
include Rack::Test::Methods
|
17
15
|
|
18
16
|
def initialize(args)
|
19
17
|
super(args)
|
20
|
-
@things = YAML.
|
21
|
-
symbolize_names: true)
|
18
|
+
@things = YAML.load_file(MGROOT + 'lib' + 'all_the_things.yaml')
|
22
19
|
end
|
23
20
|
|
24
21
|
def app
|
25
22
|
OUTER_APP
|
26
23
|
end
|
27
24
|
|
28
|
-
# Load the page
|
29
|
-
#
|
25
|
+
# Load the page 1000 times and make sure no talk titles occur
|
26
|
+
# twice
|
30
27
|
#
|
31
28
|
def test_no_repeats
|
32
29
|
1000.times do
|
@@ -36,80 +33,54 @@ class TestApp < MiniTest::Test
|
|
36
33
|
end
|
37
34
|
end
|
38
35
|
|
39
|
-
# Get all of the templates used to generate talk titles, and
|
40
|
-
# re-run the test until we've seen them all. Then we know no
|
41
|
-
# template causes a crash. That's good enough.
|
42
|
-
#
|
43
36
|
def test_default
|
37
|
+
#
|
38
|
+
# Get all of the templates used to generate talk titles, and re-run
|
39
|
+
# the test until we've seen them all. Then we know no template
|
40
|
+
# causes a crash. That's good enough.
|
41
|
+
#
|
44
42
|
templates = things[:template].map do |t|
|
45
43
|
escaped = Regexp.escape(CGI.escapeHTML(t))
|
46
|
-
matcher = escaped.gsub(/%\w+%/, '
|
47
|
-
.gsub(/FNOPS/, '\w+')
|
44
|
+
matcher = escaped.gsub(/%\w+%/, '\w+').gsub(/RAND\d+/, '\d+')
|
48
45
|
Regexp.new('^.*ttitle">' + matcher + '</span>.*$')
|
49
46
|
end
|
50
47
|
|
51
48
|
until templates.empty?
|
52
49
|
get '/'
|
53
|
-
|
54
|
-
|
55
|
-
last_response.
|
56
|
-
|
57
|
-
assert_match(/
|
58
|
-
|
59
|
-
templates.each { |t| templates.delete(t) if resp.match?(t) }
|
50
|
+
assert last_response.ok?
|
51
|
+
assert last_response.header['Content-Type'] == 'text/html;charset=utf-8'
|
52
|
+
x = last_response.body
|
53
|
+
assert_match(/The code./, x)
|
54
|
+
assert_match(/DevOps Meetup/, x)
|
55
|
+
templates.each { |t| templates.delete(t) if x.match(t) }
|
60
56
|
end
|
61
57
|
end
|
62
58
|
|
63
|
-
def
|
64
|
-
get
|
65
|
-
assert last_response.ok?
|
66
|
-
assert_instance_of(String, last_response.body)
|
67
|
-
assert_match(/^"\w+ \w+"$/, last_response.body)
|
68
|
-
assert last_response.header['Content-Type'] == 'application/json'
|
69
|
-
end
|
70
|
-
|
71
|
-
def test_api_company
|
72
|
-
get format('/api/company')
|
59
|
+
def test_api_talk
|
60
|
+
get '/api/talk'
|
73
61
|
assert last_response.ok?
|
74
|
-
assert_instance_of(String, last_response.body)
|
75
|
-
assert_match(/^"\w+.io"$/, last_response.body)
|
76
62
|
assert last_response.header['Content-Type'] == 'application/json'
|
63
|
+
resp = last_response.body
|
64
|
+
refute_empty resp
|
65
|
+
j = JSON.parse(resp)
|
66
|
+
fields = %w[talk talker role company]
|
67
|
+
assert_equal(j.keys, fields)
|
68
|
+
fields.each { |f| refute_empty j[f] }
|
69
|
+
name = j['talker'].split
|
70
|
+
assert_includes(things[:first_name], name.first)
|
71
|
+
assert_includes(things[:last_name], name.last)
|
72
|
+
assert j['company'].end_with?('.io')
|
77
73
|
end
|
78
74
|
|
79
75
|
def test_api_misc
|
80
|
-
%w[title role refreshment
|
81
|
-
get format('/api
|
76
|
+
%w[title talker company role refreshment].each do |word|
|
77
|
+
get format('/api/%s', word)
|
82
78
|
assert last_response.ok?
|
83
|
-
assert_instance_of(String, last_response.body)
|
84
79
|
assert last_response.header['Content-Type'] == 'application/json'
|
85
80
|
end
|
86
81
|
end
|
87
82
|
|
88
|
-
def
|
89
|
-
get format('/api/talk')
|
90
|
-
assert last_response.ok?
|
91
|
-
assert_instance_of(String, last_response.body)
|
92
|
-
as_obj = JSON.parse(last_response.body, symbolize_names: true)
|
93
|
-
assert_equal(%i[title talker role company], as_obj.keys)
|
94
|
-
end
|
95
|
-
|
96
|
-
def test_api_agenda
|
97
|
-
get format('/api/agenda')
|
98
|
-
assert last_response.ok?
|
99
|
-
assert_instance_of(String, last_response.body)
|
100
|
-
agenda = JSON.parse(last_response.body, symbolize_names: true)
|
101
|
-
assert_equal(%i[date location refreshment talks], agenda.keys.sort)
|
102
|
-
|
103
|
-
agenda[:talks].each do |t|
|
104
|
-
assert_equal(%i[title talker role company], t.keys)
|
105
|
-
end
|
106
|
-
|
107
|
-
assert_instance_of(String, agenda[:refreshment])
|
108
|
-
assert_instance_of(String, agenda[:date])
|
109
|
-
assert_instance_of(String, agenda[:location])
|
110
|
-
end
|
111
|
-
|
112
|
-
def test_api_not_found
|
83
|
+
def test_api_404
|
113
84
|
get '/api/no_such_thing'
|
114
85
|
assert_equal(last_response.status, 404)
|
115
86
|
end
|
data/spec/unit_spec.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require_relative '../lib/meetup-generator'
|
5
|
+
|
6
|
+
THINGS = { food_style: %w[artisan],
|
7
|
+
food: %w[flatbread],
|
8
|
+
first_name: %w[John],
|
9
|
+
last_name: %w[Smith],
|
10
|
+
job_role: %w[Neckbeard],
|
11
|
+
job_title: ['Without Portfolio'],
|
12
|
+
tech: %w[Ruby],
|
13
|
+
template: ['RAND20 %tech% things'] }.freeze
|
14
|
+
|
15
|
+
class Giblets < MeetupGenerator
|
16
|
+
def initialize; end
|
17
|
+
end
|
18
|
+
|
19
|
+
class GibletsTest < MiniTest::Test
|
20
|
+
attr_reader :m
|
21
|
+
|
22
|
+
def setup
|
23
|
+
@m = Giblets.new
|
24
|
+
m.instance_variable_set(:@lib, THINGS)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_title
|
28
|
+
x = m.title
|
29
|
+
assert_instance_of(String, x)
|
30
|
+
assert !x.empty?
|
31
|
+
refute_match(/%\w+%/, x)
|
32
|
+
refute_match(/RAND/, x)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_talk
|
36
|
+
x = m.talks(1)
|
37
|
+
assert_instance_of(Array, x)
|
38
|
+
assert_instance_of(String, x.first)
|
39
|
+
toks = x.first.split
|
40
|
+
number = toks.first.to_i
|
41
|
+
assert number > 0
|
42
|
+
assert number <= 20
|
43
|
+
assert_equal('Ruby', toks[1])
|
44
|
+
assert_equal('things', toks[2])
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_talker
|
48
|
+
assert_equal(m.talker, 'John Smith')
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_role
|
52
|
+
assert_equal(m.role, 'Neckbeard Without Portfolio')
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_company_no_e
|
56
|
+
m.instance_variable_set(:@words, %w[leadswinger])
|
57
|
+
assert_equal(m.company, 'leadswingr.io')
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_company
|
61
|
+
m.instance_variable_set(:@words, %w[Cabbage])
|
62
|
+
assert_equal(m.company, 'cabbage.io')
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_refreshment
|
66
|
+
assert_equal(m.refreshment, 'artisan flatbread')
|
67
|
+
end
|
68
|
+
end
|
data/views/default.slim
CHANGED
@@ -7,42 +7,42 @@ html
|
|
7
7
|
|
8
8
|
body
|
9
9
|
#container
|
10
|
-
h1
|
11
|
-
' #DevOps Meetup //
|
12
|
-
=> @agenda[:location]
|
13
|
-
' //
|
14
|
-
== @agenda[:date]
|
10
|
+
h1 #DevOps Meetup // Shoreditch, probably // #{(Date.today + 1).strftime("%d/%m/%Y")}
|
15
11
|
|
16
12
|
ul
|
17
13
|
li 18:00 // Introduction
|
18
14
|
|
19
15
|
li
|
20
16
|
' 18:10 // Lightning talk //
|
21
|
-
|
17
|
+
span.ttitle=@talks.pop
|
18
|
+
.tperson=@jobs.pop
|
22
19
|
|
23
20
|
li
|
24
21
|
' 18:20 //
|
25
|
-
|
22
|
+
span.ttitle=@talks.pop
|
23
|
+
.tperson=@jobs.pop
|
26
24
|
|
27
|
-
li
|
28
|
-
|
29
|
-
.indent=@agenda[:refreshment]
|
25
|
+
li 18:50 // break
|
26
|
+
.tperson=@food
|
30
27
|
|
31
28
|
li
|
32
29
|
' 19:20 //
|
33
|
-
|
30
|
+
span.ttitle=@talks.pop
|
31
|
+
.tperson=@jobs.pop
|
34
32
|
|
35
33
|
li
|
36
34
|
' 19:40 // Ignite //
|
37
|
-
|
35
|
+
span.ttitle=@talks.pop
|
36
|
+
.tperson=@jobs.pop
|
38
37
|
|
39
38
|
li
|
40
39
|
' 20:00 //
|
41
|
-
|
40
|
+
span.ttitle=@talks.pop
|
41
|
+
.tperson=@jobs.pop
|
42
42
|
|
43
43
|
li
|
44
44
|
' 20:30 // Close
|
45
|
-
.
|
45
|
+
.tperson Everyone is hiring, but no one's paying
|
46
46
|
|
47
47
|
#footer
|
48
48
|
a href='https://github.com/snltd/meetup-generator' The code.
|
@@ -5,7 +5,7 @@
|
|
5
5
|
<service_bundle type='manifest' name='snltd:sinatra:meetup-generator'>
|
6
6
|
|
7
7
|
<service
|
8
|
-
name='
|
8
|
+
name='application/sinatra/meetup-generator'
|
9
9
|
type='service'
|
10
10
|
version='1'>
|
11
11
|
|
@@ -90,7 +90,7 @@
|
|
90
90
|
</common_name>
|
91
91
|
|
92
92
|
<documentation>
|
93
|
-
<doc_link name='meetup.
|
93
|
+
<doc_link name='meetup.rfisher.co.uk' uri='http://meetup.rdfisher.co.uk' />
|
94
94
|
</documentation>
|
95
95
|
|
96
96
|
</template>
|