Ruby Kramdown breaks code block and table in a markdown - ruby

It looks that Kramdown changes the delimiter of a code block from ``` to ` when I use to_kramdown. The minimum code is below.
require 'kramdown'
code = <<END
```rb
num = 0
while num < 2 do
print("num = ", num)
end
print("End")
```
END
puts code #1
doc = Kramdown::Document.new(code)
puts doc.to_kramdown #2
This gives you:
```rb
num = 0
while num < 2 do
print("num = ", num)
end
print("End")
```
`rb
num = 0
while num < 2 do
print("num = ", num)
end
print("End")
`
How can I restore the code block with ```?
I checked KD:Documnt object and it has :codespan_delimiter=>"```". Is there any way to use it when I restore?
<KD:Document: options={:template=>"", :auto_ids=>true, :auto_id_stripping=>false, :auto_id_prefix=>"", :transliterated_header_ids=>false, :parse_block_html=>false, :parse_span_html=>true, :html_to_native=>false, :link_defs=>{}, :footnote_nr=>1, :entity_output=>:as_char, :toc_levels=>[1, 2, 3, 4, 5, 6], :line_width=>72, :latex_headers=>["section", "subsection", "subsubsection", "paragraph", "subparagraph", "subparagraph"], :smart_quotes=>["lsquo", "rsquo", "ldquo", "rdquo"], :typographic_symbols=>{}, :remove_block_html_tags=>true, :remove_span_html_tags=>false, :header_offset=>0, :syntax_highlighter=>:rouge, :syntax_highlighter_opts=>{}, :math_engine=>:mathjax, :math_engine_opts=>{}, :footnote_backlink=>"↩", :footnote_backlink_inline=>false, :footnote_prefix=>"", :remove_line_breaks_for_cjk=>false, :forbidden_inline_options=>[:template], :list_indent=>2} root=<kd:root options={:encoding=>#<Encoding:UTF-8>, :location=>1, :options=>{}, :abbrev_defs=>{}, :abbrev_attr=>{}, :footnote_count=>0} children=[<kd:p options={:location=>1} children=[<kd:codespan value="rb\nnum = 0\nwhile num < 2 do\n print(\"num = \", num)\nend\nprint(\"End\")\n" options={:codespan_delimiter=>"```", :location=>1}>]>]> warnings=[]>
I also tried Kramdown GFM Parser but it converts the code block differently as below.
num = 0
while num < 2 do
print("num = ", num)
end
print("End")
{: .language-rb}

Per the Kramdown spec:
backticks (`) are for inline code
tildas ~~~ are for code blocks.
Code Span is for Inline Code and differs from
Code Blocks.
The flavor you are currently using for code blocks (```) is Github Flavored Markdown which is why the GFM Parser/converter works. e.g.
num = 0
while num < 2 do
print("num = ", num)
end
print("End")
{: .language-rb}
Is the correct output because 4 spaces is also valid Code Block syntax.
If you want to use the kramdown gem you will have to change this to:
require 'kramdown'
code = <<END
~~~ruby
num = 0
while num < 2 do
print("num = ", num)
end
print("End")
~~~
END
doc = Kramdown::Document.new(code)
doc.to_kramdown
In which case the output is identical to the GFM Parser.

Related

Sanitizing URL strings

Say we have a string
url = "http://example.com/foo/baz/../../."
Obviously, we know from the Unix shell that ../../. essentially means to go up two directories. Hence, this URL is really going to http://example.com/. My question is, given these ../ characters in a string, how can we sanitize the URL string to point at the actual resource?
For example:
url = "http://example.com/foo/baz/../../hello.html"
url = process(url)
url = "http://example.com/hello.html"
Another:
url = "http://example.com/foo/baz/../."
url = process(url)
url = "http://example.com/foo/"
Keep in mind, the function still as to be able to take in normal URLs (ie. http://example.com) and return them as is if there is nothing to sanitize
The addressable gem can do this.
require 'addressable'
Addressable::URI.parse("http://example.com/foo/baz/../../hello.html").normalize.to_s
#=> "http://example.com/hello.html"
#!/usr/bin/env ruby
# ======
## defs:
def process(url)
url_components = url.split('/')
url_components2 = url_components.dup
current_index = 0
url_components.each do |component|
if component == '..'
url_components2.delete_at(current_index)
url_components2.delete_at(current_index-1)
current_index -= 1
elsif
component == '.'
url_components2.delete_at(current_index)
else
current_index += 1
end
end
url_resolved = url_components2.join('/')
return url_resolved
end
# =======
## tests:
urls = [
"http://example.com/foo/baz/../../.",
"http://example.com/foo/baz/../../hello.html",
"http://example.com/foo/baz/../."
]
urls.each do |url|
print url, ' => '
puts process(url)
end

How to reuse captured block in Slim and avoid duplicates?

Look at this code snippet:
require 'slim'
SLIM = <<-SLIM
- column do
= 'Text '
SLIM
def column(&block)
$column = block
end
#########
template = Slim::Template::new { SLIM }
template.render(self)
p $column.call
p $column.call
p $column.call
As you can see I have captured block (it render 'Text ' string) to $column global variable and call it 3 times. I expect that will be printed:
"Text "
"Text "
"Text "
but instead I see:
"Text "
"Text Text "
"Text Text Text "
How to capture block and avoid duplicates?
I think this is because you are passing block with = 'Text ' value, and = in Slim is accumulating values, that's why you get incremented string
Why you can't just call template.render(self) multiple times?
require 'slim'
SLIM = <<-SLIM
- column do
= 'Text '
SLIM
def column(&block)
block.call
end
#########
template = Slim::Template::new { SLIM }
p template.render(self)
p template.render(self)
p template.render(self)
Try p #{yield} directly 3 times if ypu are using slim without framework.

How do I insert a 'section' at the top of IniFile via Ruby

I have an Ini file, and I am using IniFile to help parse it.
I want to add a new section at the top of the ini file, how do I do this?
sample.ini
[Student1]
A = 1
[Student2]
B = 1
My expected result,
[Summary]
NumOfStudents=2
[Student1]
A = 1
[Student2]
B = 1
Problem: the Summary section is always inserted at bottom.
[Student1]
A = 1
[Student2]
B = 1
[Summary]
NumOfStudents=2
My Ruby script
iniFileHandle = IniFile.load(sample.ini)
numOfStudents = iniFileHandle.sections.size
iniFileHandle['Summary'] = {'NumOfStudents' => numOfStudents}
Additional
Ruby IniFile 2.0.2 Doc
From the doc, I don't find any functions to insert a section at the top.
The code of this gem is really simple, it is only one file.
It doesn't seems to be possible right now. You can implement this feature if you need it. In his code, basically he keep a section name and a hash with the variables on that section. what the []= method does is to add a new variable to the hash using its []= method. Since ruby 1.9 ruby hashes are ordered, but this method adds on the tail of it. A way to add in the front of the hash is like the following:
{front_key: "Front value"}.merge(original_hash)
Happy hacking.
1) Why is the order of the sections in an ini file relevant?
2)
my_prog.rb:
require 'inifile'
ini_file = IniFile.load("sample.ini")
numOfStudents = ini_file.sections.size
h = {
"Summary" => { "NumOfStudents" => numOfStudents }
}
ini_file.instance_eval do
p #ini #instance_eval() changes self to ini_file, and
h.merge! #ini #all instance variables are looked up in whatever
#ini = h #object is self. If you look at the inifile gem's source
end #code, the sections of the ini file are stored in a
#hash called #ini
ini_file.write
--output:--
$ cat sample.ini
[Student1]
A = 1
[Student2]
B = 1
~/ruby_programs$ ruby my_prog.rb
{"Student1"=>{"A"=>"1"}, "Student2"=>{"B"=>"1"}}
~/ruby_programs$ cat sample.ini
[Summary]
NumOfStudents = 2
[Student1]
A = 1
[Student2]
B = 1
3) Or you can do it this way:
require 'inifile'
class IniFile
attr_accessor :ini
end
ini_file = IniFile.load("sample.ini")
numOfStudents = ini_file.sections.size
h = {
"Summary" => { "NumOfStudents" => numOfStudents }
}
results = h.merge! ini_file.ini
ini_file.ini = results
ini_file.write

ruby cgi wont return method calls, but will return parameters

my environment: ruby 1.9.3p392 (2013-02-22 revision 39386) [x86_64-linux]
The thing is, I can make ruby return the parameters sent over GET. but when i'm trying to use them as arguements to my methods in if/else, ruby wont return anything and I end up with a blank page.
ph and pm return correctly:
http://127.0.0.1/cgi-bin/test.rb?hostname=node00.abit.dk&macadd=23:14:41:51:63
returns:
node00.abit.dk 23:14:41:51:63
Connection to the database (MySQL) works fine
When I test the method newHostName it outputs correctly:
puts newHostName
returns (which is correct)
node25.abit.dk
the code:
#!/usr/bin/ruby
require 'cgi'
require 'sequel'
require 'socket'
require 'timeout'
DB = Sequel.connect(:adapter=>'mysql', :host=>'localhost', :database=>'nodes', :user=>'nodeuser', :password=>'...')
#cgi-part to work
#takes 2 parameters:
#hostname & macadd
cgi = CGI.new
puts cgi.header
p = cgi.params
ph = p['hostname']
pm = p['macadd']
def nodeLookup(hostnameargv)
hostname = DB[:basenode]
h = hostname[:hostname => hostnameargv]
h1 = h[:hostname]
h2 = h[:macadd]
ary = [h1, h2]
return ary
end
def lastHostName()
#TODO: replace with correct sequel-code and NOT raw SQL
DB.fetch("SELECT hostname FROM basenode ORDER BY id DESC LIMIT 1") do |row|
return row[:hostname]
end
end
def newHostName()
org = lastHostName
#Need this 'hack' to make ruby grep for the number
#nodename e.g 'node01.abit.dk'
var1 = org[4]
var2 = org[5]
var3 = var1 + var2
sum = var3.to_i + 1
#puts sum
sum = "node" + sum.to_s + ".abit.dk"
return sum
end
def insertNewNode(newhost, newmac)
newnode = DB[:basenode]
newnode.insert(:hostname => newhost, :macadd => newmac)
return "#{newnode.count}"
end
#puts ph
#puts pm
#puts newHostName
cgi.out() do
cgi.html do
begin
if ph == "node00.abit.dk"
puts newHostName
else
puts nodeLookup(ph)
end
end
end
end
I feel like im missing something here. Any help is very much appreciated!
//M00kaw
What about modify last lines of your code as followed? CGI HTML generation methods take a block and yield the return value of the block as their content. So you should make newHostName or nodeLookup(ph) as the return value of the block passed to cgi.html(), rather than puts sth, which prints the content to your terminal and return nil. That's why cgi.html() got an empty string (nil.to_s).
#puts newHostName
cgi.out() do
cgi.html do
if ph == "node00.abit.dk"
newHostName
else
nodeLookup(ph)
end
end
end
p.s. It's conventional to indent your ruby code with 2 spaces :-)

How do I read a CSV file?

I have problems reading a CSV file with two columns separated by "\tab".
My code is:
require 'csv'
require 'rubygems'
# Globals
INFINITY = 1.0/0
if __FILE__ == $0
# Locals
data = []
fn = ''
# Argument check
if ARGV.length == 1
fn = ARGV[0]
else
puts 'Usage: kmeans.rb INPUT-FILE'
exit
end
# Get all data
CSV.foreach(fn) do |row|
x = row[0].to_f
y = row[1].to_f
p = Point.new(x,y)
data.push p
end
# Determine the number of clusters to find
puts 'Number of clusters to find:'
k = STDIN.gets.chomp!.to_i
# Run algorithm on data
clusters = kmeans(data, k)
# Graph output by running gnuplot pipe
Gnuplot.open do |gp|
# Start a new plot
Gnuplot::Plot.new(gp) do |plot|
plot.title fn
# Plot each cluster's points
clusters.each do |cluster|
# Collect all x and y coords for this cluster
x = cluster.points.collect {|p| p.x }
y = cluster.points.collect {|p| p.y }
# Plot w/o a title (clutters things up)
plot.data << Gnuplot::DataSet.new([x,y]) do |ds|
ds.notitle
end
end
end
end
end
The file is:
48.2641334571 86.4516903905
0.1140042627 35.8368597414
97.4319168245 92.8009240744
24.4614031388 18.3292584382
36.2367675367 32.8294024271
75.5836860736 68.30729977
38.6577034445 25.7701728584
28.2607136287 64.4493377817
61.5358486771 61.2195232194
I'm getting this error:
test.csv:1: syntax error, unexpected ',', expecting $end
48.2641334571,86.4516903905
^
You are just missing an end at the bottom. Your very first if is not closed.
CSV are "Comma-Separated Values". Yours are using tabs. This is not a big problem, because the CSV class can handle it, you just need to specify that your separator is a tab:
CSV.foreach(fn, { :col_sep => "\t" })
Be sure to double-check your file that it is using tabs, not spaces which are not the same.
I'm still confused about the error message, is this everything you received?

Resources