ro 4.2.0 → 4.4.0

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 (156) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +29 -8
  3. data/LICENSE +1 -1
  4. data/README.md +274 -111
  5. data/Rakefile +2 -2
  6. data/lib/ro/_lib.rb +18 -6
  7. data/lib/ro/asset.rb +23 -13
  8. data/lib/ro/collection.rb +47 -4
  9. data/lib/ro/config.rb +4 -0
  10. data/lib/ro/error.rb +5 -2
  11. data/lib/ro/html.rb +23 -0
  12. data/lib/ro/html_safe.rb +143 -0
  13. data/lib/ro/methods.rb +95 -38
  14. data/lib/ro/node.rb +78 -35
  15. data/lib/ro/path.rb +4 -0
  16. data/lib/ro/template.rb +62 -22
  17. data/lib/ro/text.rb +120 -0
  18. data/lib/ro.rb +4 -0
  19. data/public/api/ro/index-1.json +997 -79
  20. data/public/api/ro/index.json +997 -79
  21. data/public/api/ro/nerd/fastest-possible-embeddings/index.json +90 -0
  22. data/public/api/ro/nerd/ima/index.json +49 -0
  23. data/public/api/ro/nerd/index/index.json +74 -0
  24. data/public/api/ro/nerd/index-1.json +204 -0
  25. data/public/api/ro/nerd/index.json +194 -0
  26. data/public/api/ro/pages/about/index.json +60 -0
  27. data/public/api/ro/pages/contact/index.json +50 -0
  28. data/public/api/ro/pages/cv/index.json +49 -0
  29. data/public/api/ro/pages/disco/index.json +117 -0
  30. data/public/api/ro/pages/index/index.json +30 -0
  31. data/public/api/ro/pages/index-1.json +366 -0
  32. data/public/api/ro/pages/index.json +356 -0
  33. data/public/api/ro/pages/jess/index.json +62 -0
  34. data/public/api/ro/pages/now/index.json +43 -0
  35. data/public/api/ro/posts/almost-died-in-an-ice-cave/index.json +265 -0
  36. data/public/api/ro/posts/facebook-and-global-extremism/index.json +90 -0
  37. data/public/api/ro/posts/index-1.json +461 -79
  38. data/public/api/ro/posts/index.json +461 -79
  39. data/public/api/ro/posts/lemmings-considered-harmful/index.json +49 -0
  40. data/public/api/ro/posts/lost-in-the-desert/index.json +49 -0
  41. data/public/api/ro/posts/mission/index.json +49 -0
  42. data/public/api/ro/posts/return-your-laptop/index.json +61 -0
  43. data/public/ro/nerd/fastest-possible-embeddings/assets/giraffe.jpeg +0 -0
  44. data/public/ro/nerd/fastest-possible-embeddings/assets/let-me-in.jpg +0 -0
  45. data/public/ro/nerd/fastest-possible-embeddings/assets/src/fastembed.js +70 -0
  46. data/public/ro/nerd/fastest-possible-embeddings/assets/src/fastembed.rs +68 -0
  47. data/public/ro/nerd/fastest-possible-embeddings/assets/terminal.jpg +0 -0
  48. data/public/ro/nerd/fastest-possible-embeddings/attributes.yml +7 -0
  49. data/public/ro/nerd/fastest-possible-embeddings/body.md +266 -0
  50. data/public/ro/nerd/ima/assets/og.jpeg +0 -0
  51. data/public/ro/nerd/ima/attributes.yml +8 -0
  52. data/public/ro/nerd/ima/body.md +22 -0
  53. data/public/ro/nerd/index/assets/giraffe.jpeg +0 -0
  54. data/public/ro/nerd/index/assets/let-me-in.jpg +0 -0
  55. data/public/ro/nerd/index/assets/terminal.jpg +0 -0
  56. data/public/ro/nerd/index/attributes.yml +7 -0
  57. data/public/ro/nerd/index/body.md +130 -0
  58. data/public/ro/pages/about/assets/og.jpeg +0 -0
  59. data/public/ro/pages/about/assets/speak-english-pulp-fiction.gif +0 -0
  60. data/public/ro/pages/about/body.md +40 -0
  61. data/public/ro/pages/contact/assets/giraffe.jpeg +0 -0
  62. data/public/ro/pages/contact/attributes.yml +7 -0
  63. data/public/ro/pages/contact/body.md +9 -0
  64. data/public/ro/pages/cv/assets/ara.jpg +0 -0
  65. data/public/ro/pages/cv/attributes.yml +6 -0
  66. data/public/ro/pages/cv/body.md +122 -0
  67. data/public/ro/pages/disco/assets/disco.jpg +0 -0
  68. data/public/ro/pages/disco/assets/disco.png +0 -0
  69. data/public/ro/pages/disco/assets/speak-english-pulp-fiction.gif +0 -0
  70. data/public/ro/pages/disco/assets/src/environment.md +2354 -0
  71. data/public/ro/pages/disco/assets/src/fortune-500.md +2518 -0
  72. data/public/ro/pages/disco/assets/src/greed.md +2703 -0
  73. data/public/ro/pages/disco/assets/src/up-at-night.md +2337 -0
  74. data/public/ro/pages/disco/attributes.yml +9 -0
  75. data/public/ro/pages/disco/body.md +99 -0
  76. data/public/ro/pages/disco/samples/environment.md +2354 -0
  77. data/public/ro/pages/disco/samples/fortune-500.md +2518 -0
  78. data/public/ro/pages/disco/samples/greed.md +2703 -0
  79. data/public/ro/pages/disco/samples/up-at-night.md +2337 -0
  80. data/public/ro/pages/index/attributes.yml +1 -0
  81. data/public/ro/pages/index/body.md +15 -0
  82. data/public/ro/pages/jess/assets/og.jpg +0 -0
  83. data/public/ro/pages/jess/assets/speak-english-pulp-fiction.gif +0 -0
  84. data/public/ro/pages/jess/attributes.yml +7 -0
  85. data/public/ro/pages/jess/body.md +3 -0
  86. data/public/ro/pages/now/assets/speak-english-pulp-fiction.gif +0 -0
  87. data/public/ro/pages/now/attributes.yml +1 -0
  88. data/public/ro/pages/now/body.md +24 -0
  89. data/public/ro/posts/almost-died-in-an-ice-cave/assets/image1.png +0 -0
  90. data/public/ro/posts/almost-died-in-an-ice-cave/assets/image10.png +0 -0
  91. data/public/ro/posts/almost-died-in-an-ice-cave/assets/image11.png +0 -0
  92. data/public/ro/posts/almost-died-in-an-ice-cave/assets/image12.png +0 -0
  93. data/public/ro/posts/almost-died-in-an-ice-cave/assets/image13.png +0 -0
  94. data/public/ro/posts/almost-died-in-an-ice-cave/assets/image14.png +0 -0
  95. data/public/ro/posts/almost-died-in-an-ice-cave/assets/image15.png +0 -0
  96. data/public/ro/posts/almost-died-in-an-ice-cave/assets/image2.png +0 -0
  97. data/public/ro/posts/almost-died-in-an-ice-cave/assets/image3.png +0 -0
  98. data/public/ro/posts/almost-died-in-an-ice-cave/assets/image4.png +0 -0
  99. data/public/ro/posts/almost-died-in-an-ice-cave/assets/image5.png +0 -0
  100. data/public/ro/posts/almost-died-in-an-ice-cave/assets/image6.png +0 -0
  101. data/public/ro/posts/almost-died-in-an-ice-cave/assets/image7.png +0 -0
  102. data/public/ro/posts/almost-died-in-an-ice-cave/assets/image8.png +0 -0
  103. data/public/ro/posts/almost-died-in-an-ice-cave/assets/image9.png +0 -0
  104. data/public/ro/posts/almost-died-in-an-ice-cave/assets/josh-pointing.jpg +0 -0
  105. data/public/ro/posts/almost-died-in-an-ice-cave/assets/levi-rawr.png +0 -0
  106. data/public/ro/posts/almost-died-in-an-ice-cave/assets/og.jpg +0 -0
  107. data/public/ro/posts/almost-died-in-an-ice-cave/assets/purple-heart.jpg +0 -0
  108. data/public/ro/posts/almost-died-in-an-ice-cave/attributes.yml +6 -0
  109. data/public/ro/posts/almost-died-in-an-ice-cave/body.md +419 -0
  110. data/public/ro/posts/facebook-and-global-extremism/assets/background.html +125 -0
  111. data/public/ro/posts/facebook-and-global-extremism/assets/background.md +95 -0
  112. data/public/ro/posts/facebook-and-global-extremism/assets/og.jpg +0 -0
  113. data/public/ro/posts/facebook-and-global-extremism/assets/prompt.txt +122 -0
  114. data/public/ro/posts/facebook-and-global-extremism/assets/results.md +183 -0
  115. data/public/ro/posts/facebook-and-global-extremism/assets/survey.txt +190 -0
  116. data/public/ro/posts/facebook-and-global-extremism/attributes.yml +7 -0
  117. data/public/ro/posts/facebook-and-global-extremism/body.md +393 -0
  118. data/public/ro/posts/lemmings-considered-harmful/assets/lemming.jpeg +0 -0
  119. data/public/ro/posts/lemmings-considered-harmful/attributes.yml +6 -0
  120. data/public/ro/posts/lemmings-considered-harmful/body.md +43 -0
  121. data/public/ro/posts/lost-in-the-desert/assets/og.jpg +0 -0
  122. data/public/ro/posts/lost-in-the-desert/attributes.yml +6 -0
  123. data/public/ro/posts/lost-in-the-desert/body.md +7 -0
  124. data/public/ro/posts/mission/assets/og.jpg +0 -0
  125. data/public/ro/posts/mission/attributes.yml +6 -0
  126. data/public/ro/posts/mission/body.md +4 -0
  127. data/public/ro/posts/return-your-laptop/assets/og.jpg +0 -0
  128. data/public/ro/posts/return-your-laptop/assets/return-your-laptop.png +0 -0
  129. data/public/ro/posts/return-your-laptop/attributes.yml +6 -0
  130. data/public/ro/posts/return-your-laptop/body.md +58 -0
  131. data/ro.gemspec +178 -49
  132. data/scripts/speedtest.rb +324 -0
  133. data/tmp/gem-details.oe +0 -0
  134. metadata +157 -33
  135. data/public/api/ro/posts/first_post/index.json +0 -52
  136. data/public/api/ro/posts/second_post/index.json +0 -51
  137. data/public/api/ro/posts/third_post/index.json +0 -51
  138. data/public/ro/posts/first_post/assets/foo/bar/baz.jpg +0 -0
  139. data/public/ro/posts/first_post/assets/foo.jpg +0 -0
  140. data/public/ro/posts/first_post/assets/src/foo/bar.rb +0 -3
  141. data/public/ro/posts/first_post/attributes.yml +0 -2
  142. data/public/ro/posts/first_post/blurb.erb.md +0 -7
  143. data/public/ro/posts/first_post/body.md +0 -16
  144. data/public/ro/posts/first_post/testing.txt +0 -3
  145. data/public/ro/posts/second_post/assets/foo/bar/baz.jpg +0 -0
  146. data/public/ro/posts/second_post/assets/foo.jpg +0 -0
  147. data/public/ro/posts/second_post/assets/src/foo/bar.rb +0 -3
  148. data/public/ro/posts/second_post/attributes.yml +0 -2
  149. data/public/ro/posts/second_post/blurb.erb.md +0 -5
  150. data/public/ro/posts/second_post/body.md +0 -16
  151. data/public/ro/posts/third_post/assets/foo/bar/baz.jpg +0 -0
  152. data/public/ro/posts/third_post/assets/foo.jpg +0 -0
  153. data/public/ro/posts/third_post/assets/src/foo/bar.rb +0 -3
  154. data/public/ro/posts/third_post/attributes.yml +0 -2
  155. data/public/ro/posts/third_post/blurb.erb.md +0 -5
  156. data/public/ro/posts/third_post/body.md +0 -16
data/lib/ro/template.rb CHANGED
@@ -5,16 +5,14 @@ module Ro
5
5
  require 'kramdown'
6
6
  require 'kramdown-parser-gfm'
7
7
 
8
+ require_relative 'html.rb'
8
9
  require_relative 'template/rouge_formatter.rb'
9
10
 
10
- class HTML < ::String
11
- end
12
-
13
- def self.render(*args, &block)
11
+ def Template.render(*args, &block)
14
12
  render_file(*args, &block)
15
13
  end
16
14
 
17
- def self.render_file(path, options = {})
15
+ def Template.render_file(path, options = {})
18
16
  path = File.expand_path(path.to_s.strip)
19
17
  options = Map.for(options.is_a?(Hash) ? options : { context: options })
20
18
 
@@ -22,10 +20,15 @@ module Ro
22
20
  engines = File.basename(path).split('.')[1..-1]
23
21
  context = options[:context]
24
22
 
25
- render_string(content, path: path, engines: engines, context: context)
23
+ begin
24
+ render_string(content, path: path, engines: engines, context: context)
25
+ rescue Ro::Error => e
26
+ msg = e.message
27
+ Ro.error! "failed to render #{ path } with `#{ msg }`"
28
+ end
26
29
  end
27
30
 
28
- def self.render_string(content, options = {})
31
+ def Template.render_string(content, options = {})
29
32
  content = String(content).force_encoding('utf-8')
30
33
  options = Map.for(options.is_a?(Hash) ? options : { context: options })
31
34
  engines = Array(options.fetch(:engines) { ['md'] }).flatten.compact
@@ -39,22 +42,22 @@ module Ro
39
42
 
40
43
  content =
41
44
  case engine
42
- when 'txt', 'text', 'html'
43
- content
45
+ when 'html'
46
+ render_html(content)
47
+ when 'txt', 'text'
48
+ render_text(content)
44
49
  when 'erb'
45
50
  render_erb(content, context:)
46
51
  when 'md', 'markdown'
47
52
  render_markdown(content)
48
- when 'yml'
49
- data = YAML.load(content)
50
- pod = Ro.pod(data)
51
- Ro.mapify(data)
53
+ when 'yml', 'yaml'
54
+ render_yaml(content)
52
55
  when 'json'
53
- data = JSON.parse(content)
54
- pod = Ro.pod(data)
55
- Ro.mapify(data)
56
+ render_json(content)
56
57
  when 'rb'
57
- eval(content)
58
+ render_ruby(content)
59
+ when 'txt', 'text'
60
+ render_text(content)
58
61
  else
59
62
  Ro.error!("no engine found for engine=#{ engine.inspect } engines=#{ engines.inspect }")
60
63
  end
@@ -63,7 +66,36 @@ module Ro
63
66
  content
64
67
  end
65
68
 
66
- def self.render_erb(content, options = {})
69
+ def Template.render_html(html)
70
+ HTML.new(html)
71
+ end
72
+
73
+ def Template.render_json(json)
74
+ data = JSON.parse(json)
75
+ Ro.mapify(data)
76
+ end
77
+
78
+ def Template.render_yaml(yaml)
79
+ data = YAML.load(yaml)
80
+ Ro.mapify(data)
81
+ end
82
+
83
+ def Template.render_ruby(code)
84
+ string = IO.popen('ruby', 'w+'){|ruby| ruby.puts(code); ruby.close_write; ruby.read}
85
+
86
+ if $? == 0
87
+ string
88
+ else
89
+ Ro.error!("ruby:\n\n#{ code }")
90
+ end
91
+ end
92
+
93
+ def Template.render_text(text)
94
+ html = Text.render(text)
95
+ HTML.new(html)
96
+ end
97
+
98
+ def Template.render_erb(content, options = {})
67
99
  content = String(content).force_encoding('utf-8')
68
100
  options = Map.for(options.is_a?(Hash) ? options : { context: options })
69
101
  context = options[:context]
@@ -82,27 +114,35 @@ module Ro
82
114
  HTML.new(html)
83
115
  end
84
116
 
85
- def self.render_markdown(content, options = {})
117
+ def Template.render_markdown(content, options = {})
86
118
  content = String(content).force_encoding('utf-8')
87
119
  options = Map.for(options.is_a?(Hash) ? options : { context: options })
88
120
 
89
121
  theme = options.fetch(:theme) { Ro.config.md_theme }
90
122
 
123
+ parsed = FrontMatterParser::Parser.new(:md).call(content)
124
+ front_matter = parsed.front_matter
125
+ content = parsed.content
126
+
91
127
  opts = {
92
128
  input: 'GFM',
129
+ hard_wrap: false,
93
130
  syntax_highlighter_opts: { formatter: RougeFormatter, theme: theme }
94
131
  }
95
132
 
96
- HTML.new(
133
+ div =
97
134
  <<~_____
98
135
  <div class="ro markdown">
99
136
  #{ ::Kramdown::Document.new(content, opts).to_html }
100
137
  </div>
101
138
  _____
102
- )
139
+
140
+ html = Rinku.auto_link(div, :all, 'target="_blank"')
141
+
142
+ HTML.new(html, front_matter:)
103
143
  end
104
144
 
105
- def self.render_src(path, options = {})
145
+ def Template.render_src(path, options = {})
106
146
  path = File.expand_path(path.to_s.strip)
107
147
  options = Map.for(options.is_a?(Hash) ? options : { context: options })
108
148
 
data/lib/ro/text.rb ADDED
@@ -0,0 +1,120 @@
1
+ module Ro
2
+ require 'cgi'
3
+
4
+ module Text
5
+ def render(text)
6
+ text = text.to_s.strip
7
+ return '' if text.empty?
8
+
9
+ text = escape_html(text)
10
+ text = auto_link_urls(text)
11
+ text = auto_link_email_addresses(text)
12
+ text = paragraphs_for(text)
13
+
14
+ return text
15
+ end
16
+
17
+ def paragraphs_for(text)
18
+ paragraphs = text.split(%r`\n\n+`).map{|chunk| lines_for(chunk)}
19
+ paragraphs.map{|p| "<p>\n#{ p }\n</p>"}.join("\n\n").strip
20
+ end
21
+
22
+ def lines_for(text)
23
+ text.strip.gsub(/\n/, "<br />\n")
24
+ end
25
+
26
+ def escape_html(text)
27
+ CGI.escapeHTML(text)
28
+ end
29
+
30
+ AUTO_LINK_RE = %r{
31
+ (?: ((?:ed2k|ftp|http|https|irc|mailto|news|gopher|nntp|telnet|webcal|xmpp|callto|feed|svn|urn|aim|rsync|tag|ssh|sftp|rtsp|afs|file):)// | www\.\w )
32
+ [^\s<\u00A0"]+
33
+ }ix
34
+
35
+ # regexps for determining context, used high-volume
36
+ AUTO_LINK_CRE = [/<[^>]+$/, /^[^>]*>/, /<a\b.*?>/i, /<\/a>/i]
37
+
38
+ AUTO_EMAIL_LOCAL_RE = /[\w.!#\$%&'*\/=?^`{|}~+-]/
39
+ AUTO_EMAIL_RE = /(?<!#{AUTO_EMAIL_LOCAL_RE})[\w.!#\$%+-]\.?#{AUTO_EMAIL_LOCAL_RE}*@[\w-]+(?:\.[\w-]+)+/
40
+
41
+ BRACKETS = { ']' => '[', ')' => '(', '}' => '{' }
42
+
43
+ WORD_PATTERN = '\p{Word}'
44
+
45
+ # Turns all urls into clickable links. If a block is given, each url
46
+ # is yielded and the result is used as the link text.
47
+ def auto_link_urls(text)
48
+ text.gsub(AUTO_LINK_RE) do
49
+ scheme, href = $1, $&
50
+ punctuation = []
51
+ trailing_gt = ""
52
+
53
+ if auto_linked?($`, $')
54
+ # do not change string; URL is already linked
55
+ href
56
+ else
57
+ # don't include trailing punctuation character as part of the URL
58
+ while href.sub!(/[^#{WORD_PATTERN}\/\-=;]$/, '')
59
+ punctuation.push $&
60
+ if opening = BRACKETS[punctuation.last] and href.scan(opening).size > href.scan(punctuation.last).size
61
+ href << punctuation.pop
62
+ break
63
+ end
64
+ end
65
+
66
+ # don't include trailing &gt; entities as part of the URL
67
+ trailing_gt = $& if href.sub!(/&gt;$/, '')
68
+ href = 'http://' + href unless scheme
69
+ link = escape_html(href)
70
+ "<a href='#{ link }'>#{ link }</a>" + punctuation.reverse.join('') + trailing_gt
71
+ end
72
+ end
73
+ end
74
+
75
+ # Turns all email addresses into clickable links. If a block is given,
76
+ # each email is yielded and the result is used as the link text.
77
+ def auto_link_email_addresses(text)
78
+ text.gsub(AUTO_EMAIL_RE) do
79
+ text = $&
80
+
81
+ if auto_linked?($`, $')
82
+ text
83
+ else
84
+ email = escape_html(text)
85
+ "<a href='mailto:#{ email }'>#{ email }</a>"
86
+ end
87
+ end
88
+ end
89
+
90
+ # Detects already linked context or position in the middle of a tag
91
+ def auto_linked?(left, right)
92
+ (left =~ AUTO_LINK_CRE[0] and right =~ AUTO_LINK_CRE[1]) or
93
+ (left.rindex(AUTO_LINK_CRE[2]) and $' !~ AUTO_LINK_CRE[3])
94
+ end
95
+
96
+ extend self
97
+ end
98
+ end
99
+
100
+
101
+ if $0 == __FILE__
102
+ text = <<~____
103
+ this is a paragraph that is very long this is a paragraph that is very long this is a paragraph that is very long this is a paragraph that is very long
104
+ this is a paragraph that is very long this is a paragraph that is very long this is a paragraph that is very long this is a paragraph that is very long
105
+
106
+ this is a paragraph that is very long this is a paragraph that is very long this is a paragraph that is very long this is a paragraph that is very long
107
+
108
+ - a
109
+ - b
110
+ - c
111
+
112
+ & < > me
113
+
114
+ http://drawohara.io>
115
+
116
+ ara.t.howard@gmail.com
117
+ ____
118
+
119
+ puts Ro::Text.render(text)
120
+ end
data/lib/ro.rb CHANGED
@@ -31,6 +31,7 @@ module Ro
31
31
  :root => ENV['RO_ROOT'],
32
32
  :build => ENV['RO_BUILD'],
33
33
  :url => ENV['RO_URL'],
34
+ :img_url => ENV['RO_IMG_URL'],
34
35
  :page_size => ENV['RO_PAGE_SIZE'],
35
36
  :log => ENV['RO_LOG'],
36
37
  :debug => ENV['RO_DEBUG'],
@@ -44,6 +45,7 @@ module Ro
44
45
  :root => './public/ro',
45
46
  :build => './public/api/ro',
46
47
  :url => "/ro",
48
+ :img_url => "/ro",
47
49
  :page_size => 42,
48
50
  :log => nil,
49
51
  :debug => nil,
@@ -61,10 +63,12 @@ module Ro
61
63
  # v
62
64
  def initialize!
63
65
  Ro.load %w[
66
+ html.rb
64
67
  error.rb
65
68
  klass.rb
66
69
  slug.rb
67
70
  path.rb
71
+ text.rb
68
72
  template.rb
69
73
  methods.rb
70
74
  config.rb