meetup-generator 0.0.20210128 → 1.2.84
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.
- 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>
|