vanilla 1.17 → 1.17.1

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.
Files changed (56) hide show
  1. data/Rakefile +21 -7
  2. data/bin/vanilla +2 -2
  3. data/lib/vanilla.rb +10 -7
  4. data/lib/vanilla/app.rb +57 -97
  5. data/lib/vanilla/config.rb +46 -0
  6. data/lib/vanilla/console.rb +1 -1
  7. data/lib/vanilla/renderers/base.rb +12 -2
  8. data/lib/vanilla/request.rb +9 -34
  9. data/lib/vanilla/routing.rb +34 -0
  10. data/lib/vanilla/test_helper.rb +10 -7
  11. data/pristine_app/Gemfile.lock +35 -0
  12. data/pristine_app/application.rb +2 -4
  13. data/pristine_app/public/vanilla.css +299 -9
  14. data/pristine_app/soups/base/layout.snip +11 -7
  15. data/pristine_app/soups/base/start.snip +15 -14
  16. data/pristine_app/soups/system/current_snip.rb +2 -2
  17. data/pristine_app/soups/system/feed.rb +30 -0
  18. data/pristine_app/soups/system/index.rb +3 -3
  19. data/pristine_app/soups/system/link_to.rb +5 -1
  20. data/pristine_app/soups/system/link_to_current_snip.rb +2 -3
  21. data/pristine_app/soups/tutorial/tutorial-layout.snip +9 -2
  22. data/pristine_app/soups/tutorial/tutorial-links.snip +2 -1
  23. data/pristine_app/soups/tutorial/tutorial-removing.snip.markdown +8 -0
  24. data/pristine_app/soups/tutorial/tutorial-renderers.snip.markdown +10 -4
  25. data/pristine_app/soups/tutorial/tutorial.snip.markdown +0 -1
  26. data/pristine_app/soups/tutorial/vanilla-rb.snip +4 -6
  27. data/pristine_app/tmp/restart.txt +0 -0
  28. data/test/core/configuration_test.rb +89 -0
  29. data/test/{dynasnip_test.rb → core/dynasnip_test.rb} +0 -0
  30. data/test/{renderers → core/renderers}/base_renderer_test.rb +37 -0
  31. data/test/{renderers → core/renderers}/erb_renderer_test.rb +0 -0
  32. data/test/{renderers → core/renderers}/haml_renderer_test.rb +0 -0
  33. data/test/{renderers → core/renderers}/markdown_renderer_test.rb +0 -0
  34. data/test/{renderers → core/renderers}/raw_renderer_test.rb +0 -0
  35. data/test/{renderers → core/renderers}/ruby_renderer_test.rb +0 -0
  36. data/test/core/routing_test.rb +30 -0
  37. data/test/{snip_inclusion_test.rb → core/snip_inclusion_test.rb} +0 -0
  38. data/test/{snip_reference_parser_test.rb → core/snip_reference_parser_test.rb} +0 -0
  39. data/test/{test_helper.rb → core/test_helper.rb} +5 -4
  40. data/test/core/vanilla_app_test.rb +51 -0
  41. data/test/{vanilla_presenting_test.rb → core/vanilla_presenting_test.rb} +15 -1
  42. data/test/{vanilla_request_test.rb → core/vanilla_request_test.rb} +0 -0
  43. data/test/pristine_app/current_snip_test.rb +46 -0
  44. data/test/pristine_app/feed_test.rb +47 -0
  45. data/test/pristine_app/index_test.rb +34 -0
  46. data/test/pristine_app/link_to_current_snip_test.rb +11 -0
  47. data/test/pristine_app/link_to_test.rb +27 -0
  48. data/test/pristine_app/page_title_test.rb +15 -0
  49. data/test/pristine_app/raw_test.rb +24 -0
  50. data/test/pristine_app/test_helper.rb +25 -0
  51. metadata +83 -42
  52. data/lib/vanilla/routes.rb +0 -18
  53. data/test/dynasnips/link_to_current_snip_test.rb +0 -19
  54. data/test/dynasnips/link_to_test.rb +0 -27
  55. data/test/dynasnips/page_title_test.rb +0 -19
  56. data/test/vanilla_app_test.rb +0 -111
@@ -66,6 +66,20 @@ context "When presenting" do
66
66
  end
67
67
  end
68
68
 
69
+ context "the root URL" do
70
+ should "render the start snip by default" do
71
+ create_snip :name => "start", :content => "default"
72
+ assert_response_body "<tag>default</tag>", "/"
73
+ end
74
+
75
+ should "render any custom-set root snip if provided" do
76
+ create_snip :name => "start", :content => "default"
77
+ create_snip :name => "custom", :content => "custom"
78
+ app.config.root_snip = "custom"
79
+ assert_response_body "<tag>custom</tag>", "/"
80
+ end
81
+ end
82
+
69
83
  context "a snip with a custom layout" do
70
84
  should "render the snips contents within that layout" do
71
85
  create_snip :name => "custom-layout", :content => "<custom>{current_snip}</custom>"
@@ -100,7 +114,7 @@ context "When presenting" do
100
114
 
101
115
  context "and a custom default renderer has been provided" do
102
116
  should "use that renderer" do
103
- app.config[:default_renderer] = ::Vanilla::Renderers::Bold
117
+ app.config.default_renderer = ::Vanilla::Renderers::Bold
104
118
  create_snip :name => "layout", :content => "{test}", :render_as => "base"
105
119
  create_snip :name => "test", :content => "test"
106
120
  assert_response_body "<b>test</b>", "/test"
@@ -0,0 +1,46 @@
1
+ require "test_helper"
2
+
3
+ context "The current_snip dynasnip" do
4
+ should "render the snip from the current request" do
5
+ set_main_template "<layout>{current_snip}</layout>"
6
+ create_snip :name => "test", :content => "test"
7
+
8
+ visit "/test"
9
+
10
+ assert page.has_css?("layout", :content => "test")
11
+ end
12
+
13
+ should "render a given attribute of the current snip" do
14
+ create_snip :name => "test", :content => "this is my {current_snip part}", :part => "underbelly"
15
+ visit "/test"
16
+ assert page.has_content?("this is my underbelly")
17
+ end
18
+
19
+ should "render based on the requested snip, not the including snip" do
20
+ create_snip :name => "test", :content => "this is my {current_snip part}", :part => "underbelly"
21
+ create_snip :name => "blah", :content => "{test}", :part => "flange"
22
+ visit "/blah"
23
+ assert page.has_content?("this is my flange")
24
+ end
25
+
26
+ should "be able to handle snips with spaces in their names" do
27
+ create_snip :name => "test snip", :content => "this is a test"
28
+ visit "/test+snip"
29
+ assert page.has_content?("this is a test")
30
+ end
31
+
32
+ context "when the requested snip is missing" do
33
+ setup do
34
+ set_main_template "<layout>{current_snip}</layout>"
35
+ visit "/monkey"
36
+ end
37
+
38
+ should "render an explanatory message" do
39
+ assert page.has_content?(%{Couldn't find snip "monkey"})
40
+ end
41
+
42
+ should "set the response code to 404" do
43
+ assert_equal 404, page.status_code
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,47 @@
1
+ require "test_helper"
2
+ require "atom"
3
+
4
+ context "The feed dynasnip" do
5
+ should "include snips" do
6
+ app.soup.stubs(:all_snips).returns([
7
+ snip(:name => "Hello", :content => "This is the content"),
8
+ snip(:name => "Goodbye", :content => "More content")
9
+ ])
10
+
11
+ visit "/feed.xml"
12
+
13
+ feed = Atom::Feed.load_feed(page.source)
14
+ assert_equal 2, feed.entries.length
15
+ end
16
+
17
+ should "included rendered snip contents" do
18
+ app.soup.stubs(:all_snips).returns([
19
+ snip(:name => "Hello", :content => "This is *the* content", :render_as => "markdown")
20
+ ])
21
+
22
+ visit "/feed.xml"
23
+
24
+ feed = Atom::Feed.load_feed(page.source)
25
+ assert_equal "<p>This is <em>the</em> content</p>", feed.entries.first.content
26
+ end
27
+
28
+ should "ensure that all links are made absolute"
29
+
30
+ context "each entry" do
31
+ setup do
32
+ end
33
+ should "set the name to be the name of the snip"
34
+ should "use the title of the snip as name if present"
35
+ should "set the authors"
36
+ should "include a link to the snip"
37
+ should "set the ID"
38
+ should "set the published date"
39
+ should "set the updated at"
40
+ end
41
+
42
+ private
43
+
44
+ def snip(attributes)
45
+ Soup::Snip.new(attributes, nil)
46
+ end
47
+ end
@@ -0,0 +1,34 @@
1
+ require "test_helper"
2
+
3
+ context "The index dynasnip" do
4
+ should "render links to every snip with the most recently updated first" do
5
+ app.soup.stubs(:all_snips).returns([
6
+ snip(:name => "alpha", :updated_at => Time.at(10)),
7
+ snip(:name => "beta", :updated_at => Time.at(20)),
8
+ snip(:name => "gamma", :updated_at => Time.at(40)),
9
+ snip(:name => "delta", :updated_at => Time.at(30))
10
+ ])
11
+
12
+ visit "/index"
13
+ links = page.all("ol#index li a").map { |l| l.text }
14
+ assert_equal %w(gamma delta beta alpha), links
15
+ end
16
+
17
+ should "order snips without updated_at as if they were updated a long time ago" do
18
+ app.soup.stubs(:all_snips).returns([
19
+ snip(:name => "alpha", :updated_at => Time.at(10)),
20
+ snip(:name => "beta", :updated_at => Time.at(20)),
21
+ snip(:name => "gamma")
22
+ ])
23
+
24
+ visit "/index"
25
+ links = page.all("ol#index li a").map { |l| l.text }
26
+ assert_equal %w(beta alpha gamma), links
27
+ end
28
+
29
+ private
30
+
31
+ def snip(attributes)
32
+ Soup::Snip.new(attributes, nil)
33
+ end
34
+ end
@@ -0,0 +1,11 @@
1
+ require "test_helper"
2
+
3
+ context "The link_to_current_snip dynasnip" do
4
+ should "create a link to the snip that was requested" do
5
+ create_snip :name => "a", :content => "{b}"
6
+ create_snip :name => "b", :content => "<div id='x'>{link_to_current_snip}</div>"
7
+
8
+ visit "/a"
9
+ assert page.has_css?("#x a[href='/a']")
10
+ end
11
+ end
@@ -0,0 +1,27 @@
1
+ require "test_helper"
2
+
3
+ context "The link_to dynasnip" do
4
+ should "render a link to the given snip using the snip name as text" do
5
+ create_snip :name => "test", :content => "<div id='x'>this is a {link_to test}.</div>"
6
+ visit "/test"
7
+ assert page.find("#x a[href='/test']").has_content?('test')
8
+ end
9
+
10
+ should "render a link to the given snip using custom link text" do
11
+ create_snip :name => "test", :content => "<div id='x'>this is a {link_to test, my link}.</div>"
12
+ visit "/test"
13
+ assert page.find("#x a[href='/test']").has_content?('my link')
14
+ end
15
+
16
+ should "render a link to the given snip and part" do
17
+ create_snip :name => "test", :content => "<div id='x'>this is a {link_to test, test, part}.</div>"
18
+ visit "/test"
19
+ assert page.find("#x a[href='/test/part']").has_content?('test')
20
+ end
21
+
22
+ should "add a 'missing' class where the snip does not exist" do
23
+ create_snip :name => "test", :content => "<div id='x'>this is a {link_to blah}.</div>"
24
+ visit "/test"
25
+ assert page.find("#x a.missing[href='/blah']")
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ require "test_helper"
2
+
3
+ context "The page_title dynasnip" do
4
+ should "render as the requested snip name if that snip has no title" do
5
+ visit "/"
6
+ assert page.has_css?("head title", :content => "start"), page.source
7
+ end
8
+
9
+ should "render as the requested snip's page_title when that attribute is present" do
10
+ create_snip :name => "test", :content => "test", :page_title => "This is a test"
11
+
12
+ visit "/test"
13
+ assert page.has_css?("head title", :content => "This is a test")
14
+ end
15
+ end
@@ -0,0 +1,24 @@
1
+ require "test_helper"
2
+
3
+ context "The raw dynasnip" do
4
+ should "render the snip given in its raw form" do
5
+ create_snip :name => "a", :content => "{b}"
6
+ create_snip :name => "test", :content => "<div id='x'>{raw a}</div>"
7
+ visit "/test"
8
+ assert page.has_css?("#x", :content => "&#123;b&#125;")
9
+ end
10
+
11
+ should "escape html tags" do
12
+ create_snip :name => "a", :content => "<b></b>"
13
+ create_snip :name => "test", :content => "<div id='x'>{raw a}</div>"
14
+ visit "/test"
15
+ assert page.has_css?("#x", :content => "&lt;b&gt;&lt;/b&gt;")
16
+ end
17
+
18
+ should "render a raw part" do
19
+ create_snip :name => "a", :content => "x", :bit => "a<b"
20
+ create_snip :name => "test", :content => "<div id='x'>{raw a, bit}</div>"
21
+ visit "/test"
22
+ assert page.has_css?("#x", :content => "a&lt;b")
23
+ end
24
+ end
@@ -0,0 +1,25 @@
1
+ $LOAD_PATH.unshift(File.expand_path("../../../lib"), __FILE__)
2
+ require "bundler/setup"
3
+ require "kintama"
4
+ require "kintama/mocha"
5
+ require "vanilla/test_helper"
6
+ require 'capybara'
7
+ require 'capybara/dsl'
8
+
9
+ require File.expand_path("../../../pristine_app/application", __FILE__)
10
+
11
+ module TestHelper
12
+ include Vanilla::TestHelper
13
+ end
14
+
15
+ Kintama.include TestHelper
16
+ Kintama.include Capybara
17
+
18
+ Kintama.setup do
19
+ vanilla_setup
20
+ Capybara.app = app
21
+ end
22
+
23
+ Kintama.teardown do
24
+ vanilla_teardown
25
+ end
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vanilla
3
3
  version: !ruby/object:Gem::Version
4
- hash: 45
4
+ hash: 81
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 17
9
- version: "1.17"
9
+ - 1
10
+ version: 1.17.1
10
11
  platform: ruby
11
12
  authors:
12
13
  - James Adam
@@ -14,7 +15,7 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2011-05-05 00:00:00 +01:00
18
+ date: 2011-07-24 00:00:00 -05:00
18
19
  default_executable:
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
@@ -29,26 +30,26 @@ dependencies:
29
30
  - 9
30
31
  - 1
31
32
  version: 0.9.1
32
- requirement: *id001
33
+ type: :runtime
33
34
  prerelease: false
35
+ requirement: *id001
34
36
  name: rack
35
- type: :runtime
36
37
  - !ruby/object:Gem::Dependency
37
38
  version_requirements: &id002 !ruby/object:Gem::Requirement
38
39
  none: false
39
40
  requirements:
40
41
  - - ">="
41
42
  - !ruby/object:Gem::Version
42
- hash: 27
43
+ hash: 7
43
44
  segments:
44
45
  - 1
45
46
  - 0
46
- - 6
47
- version: 1.0.6
48
- requirement: *id002
47
+ - 8
48
+ version: 1.0.8
49
+ type: :runtime
49
50
  prerelease: false
51
+ requirement: *id002
50
52
  name: soup
51
- type: :runtime
52
53
  - !ruby/object:Gem::Dependency
53
54
  version_requirements: &id003 !ruby/object:Gem::Requirement
54
55
  none: false
@@ -61,10 +62,10 @@ dependencies:
61
62
  - 3
62
63
  - 5
63
64
  version: 0.3.5
64
- requirement: *id003
65
+ type: :runtime
65
66
  prerelease: false
67
+ requirement: *id003
66
68
  name: ratom
67
- type: :runtime
68
69
  - !ruby/object:Gem::Dependency
69
70
  version_requirements: &id004 !ruby/object:Gem::Requirement
70
71
  none: false
@@ -77,10 +78,10 @@ dependencies:
77
78
  - 1
78
79
  - 1
79
80
  version: 4.1.1
80
- requirement: *id004
81
+ type: :runtime
81
82
  prerelease: false
83
+ requirement: *id004
82
84
  name: RedCloth
83
- type: :runtime
84
85
  - !ruby/object:Gem::Dependency
85
86
  version_requirements: &id005 !ruby/object:Gem::Requirement
86
87
  none: false
@@ -93,10 +94,10 @@ dependencies:
93
94
  - 0
94
95
  - 0
95
96
  version: 1.0.0
96
- requirement: *id005
97
+ type: :runtime
97
98
  prerelease: false
99
+ requirement: *id005
98
100
  name: BlueCloth
99
- type: :runtime
100
101
  - !ruby/object:Gem::Dependency
101
102
  version_requirements: &id006 !ruby/object:Gem::Requirement
102
103
  none: false
@@ -108,10 +109,10 @@ dependencies:
108
109
  - 3
109
110
  - 1
110
111
  version: "3.1"
111
- requirement: *id006
112
+ type: :runtime
112
113
  prerelease: false
114
+ requirement: *id006
113
115
  name: haml
114
- type: :runtime
115
116
  - !ruby/object:Gem::Dependency
116
117
  version_requirements: &id007 !ruby/object:Gem::Requirement
117
118
  none: false
@@ -124,10 +125,10 @@ dependencies:
124
125
  - 2
125
126
  - 0
126
127
  version: 1.2.0
127
- requirement: *id007
128
+ type: :runtime
128
129
  prerelease: false
130
+ requirement: *id007
129
131
  name: parslet
130
- type: :runtime
131
132
  - !ruby/object:Gem::Dependency
132
133
  version_requirements: &id008 !ruby/object:Gem::Requirement
133
134
  none: false
@@ -140,10 +141,10 @@ dependencies:
140
141
  - 5
141
142
  - 7
142
143
  version: 0.5.7
143
- requirement: *id008
144
+ type: :runtime
144
145
  prerelease: false
146
+ requirement: *id008
145
147
  name: rack-test
146
- type: :runtime
147
148
  - !ruby/object:Gem::Dependency
148
149
  version_requirements: &id009 !ruby/object:Gem::Requirement
149
150
  none: false
@@ -156,10 +157,10 @@ dependencies:
156
157
  - 1
157
158
  - 6
158
159
  version: 0.1.6
159
- requirement: *id009
160
+ type: :development
160
161
  prerelease: false
162
+ requirement: *id009
161
163
  name: kintama
162
- type: :development
163
164
  - !ruby/object:Gem::Dependency
164
165
  version_requirements: &id010 !ruby/object:Gem::Requirement
165
166
  none: false
@@ -170,10 +171,38 @@ dependencies:
170
171
  segments:
171
172
  - 0
172
173
  version: "0"
173
- requirement: *id010
174
+ type: :development
174
175
  prerelease: false
176
+ requirement: *id010
175
177
  name: mocha
178
+ - !ruby/object:Gem::Dependency
179
+ version_requirements: &id011 !ruby/object:Gem::Requirement
180
+ none: false
181
+ requirements:
182
+ - - ">="
183
+ - !ruby/object:Gem::Version
184
+ hash: 3
185
+ segments:
186
+ - 0
187
+ version: "0"
176
188
  type: :development
189
+ prerelease: false
190
+ requirement: *id011
191
+ name: capybara
192
+ - !ruby/object:Gem::Dependency
193
+ version_requirements: &id012 !ruby/object:Gem::Requirement
194
+ none: false
195
+ requirements:
196
+ - - ">="
197
+ - !ruby/object:Gem::Version
198
+ hash: 3
199
+ segments:
200
+ - 0
201
+ version: "0"
202
+ type: :development
203
+ prerelease: false
204
+ requirement: *id012
205
+ name: launchy
177
206
  description:
178
207
  email: james@lazyatom.com.com
179
208
  executables:
@@ -186,23 +215,31 @@ files:
186
215
  - Rakefile
187
216
  - README
188
217
  - .gemtest
189
- - test/dynasnip_test.rb
190
- - test/dynasnips/link_to_current_snip_test.rb
191
- - test/dynasnips/link_to_test.rb
192
- - test/dynasnips/page_title_test.rb
193
- - test/renderers/base_renderer_test.rb
194
- - test/renderers/erb_renderer_test.rb
195
- - test/renderers/haml_renderer_test.rb
196
- - test/renderers/markdown_renderer_test.rb
197
- - test/renderers/raw_renderer_test.rb
198
- - test/renderers/ruby_renderer_test.rb
199
- - test/snip_inclusion_test.rb
200
- - test/snip_reference_parser_test.rb
201
- - test/test_helper.rb
202
- - test/vanilla_app_test.rb
203
- - test/vanilla_presenting_test.rb
204
- - test/vanilla_request_test.rb
218
+ - test/core/configuration_test.rb
219
+ - test/core/dynasnip_test.rb
220
+ - test/core/renderers/base_renderer_test.rb
221
+ - test/core/renderers/erb_renderer_test.rb
222
+ - test/core/renderers/haml_renderer_test.rb
223
+ - test/core/renderers/markdown_renderer_test.rb
224
+ - test/core/renderers/raw_renderer_test.rb
225
+ - test/core/renderers/ruby_renderer_test.rb
226
+ - test/core/routing_test.rb
227
+ - test/core/snip_inclusion_test.rb
228
+ - test/core/snip_reference_parser_test.rb
229
+ - test/core/test_helper.rb
230
+ - test/core/vanilla_app_test.rb
231
+ - test/core/vanilla_presenting_test.rb
232
+ - test/core/vanilla_request_test.rb
233
+ - test/pristine_app/current_snip_test.rb
234
+ - test/pristine_app/feed_test.rb
235
+ - test/pristine_app/index_test.rb
236
+ - test/pristine_app/link_to_current_snip_test.rb
237
+ - test/pristine_app/link_to_test.rb
238
+ - test/pristine_app/page_title_test.rb
239
+ - test/pristine_app/raw_test.rb
240
+ - test/pristine_app/test_helper.rb
205
241
  - lib/vanilla/app.rb
242
+ - lib/vanilla/config.rb
206
243
  - lib/vanilla/console.rb
207
244
  - lib/vanilla/dynasnip.rb
208
245
  - lib/vanilla/renderers/base.rb
@@ -215,7 +252,7 @@ files:
215
252
  - lib/vanilla/renderers/textile.rb
216
253
  - lib/vanilla/renderers.rb
217
254
  - lib/vanilla/request.rb
218
- - lib/vanilla/routes.rb
255
+ - lib/vanilla/routing.rb
219
256
  - lib/vanilla/snip_reference_parser.rb
220
257
  - lib/vanilla/static.rb
221
258
  - lib/vanilla/test_helper.rb
@@ -224,6 +261,7 @@ files:
224
261
  - pristine_app/application.rb
225
262
  - pristine_app/config.ru
226
263
  - pristine_app/Gemfile
264
+ - pristine_app/Gemfile.lock
227
265
  - pristine_app/public/vanilla.css
228
266
  - pristine_app/README
229
267
  - pristine_app/soups/base/layout.snip
@@ -234,6 +272,7 @@ files:
234
272
  - pristine_app/soups/extras/url_to.rb
235
273
  - pristine_app/soups/system/current_snip.rb
236
274
  - pristine_app/soups/system/debug.rb
275
+ - pristine_app/soups/system/feed.rb
237
276
  - pristine_app/soups/system/index.rb
238
277
  - pristine_app/soups/system/link_to.rb
239
278
  - pristine_app/soups/system/link_to_current_snip.rb
@@ -252,10 +291,12 @@ files:
252
291
  - pristine_app/soups/tutorial/tutorial-dynasnips.snip.markdown
253
292
  - pristine_app/soups/tutorial/tutorial-layout.snip
254
293
  - pristine_app/soups/tutorial/tutorial-links.snip
294
+ - pristine_app/soups/tutorial/tutorial-removing.snip.markdown
255
295
  - pristine_app/soups/tutorial/tutorial-renderers.snip.markdown
256
296
  - pristine_app/soups/tutorial/tutorial.snip.markdown
257
297
  - pristine_app/soups/tutorial/vanilla-rb.snip
258
298
  - pristine_app/soups/tutorial/vanilla.snip
299
+ - pristine_app/tmp/restart.txt
259
300
  has_rdoc: true
260
301
  homepage: http://github.com/lazyatom/vanilla-rb
261
302
  licenses: []