var entry = entries[path]
if not entry.is_dirty then continue
var name = entry.name
- if entry.has_source then name = entry.src_path.to_s
+ if entry.has_source then name = entry.src_path.as(not null)
if entry.is_new then
print " + {name}"
else
fun need_render(src, target: String): Bool do
if force_render then return true
if not target.file_exists then return true
- return src.file_stat.mtime >= target.file_stat.mtime
+ return src.file_stat.as(not null).mtime >= target.file_stat.as(not null).mtime
end
# Create a new `WikiSection`.
# Used to translate ids in beautiful page names.
fun pretty_name(name: String): String do
name = name.replace("_", " ")
- name = name.capitalized
+ name = name.capitalized(keep_upper=true)
return name
end
end
# Returns `-1` if not `has_source`.
fun create_time: Int do
if not has_source then return -1
- return src_full_path.file_stat.ctime
+ return src_full_path.as(not null).file_stat.as(not null).ctime
end
# Entry last modification time.
# Returns `-1` if not `has_source`.
fun last_edit_time: Int do
if not has_source then return -1
- return src_full_path.file_stat.mtime
+ return src_full_path.as(not null).file_stat.as(not null).mtime
end
# Entry list rendering time.
# Returns `-1` if `is_new`.
fun last_render_time: Int do
if is_new then return -1
- return out_full_path.file_stat.mtime
+ return out_full_path.file_stat.as(not null).mtime
end
# Entries hierarchy
# then returns the main wiki template file.
fun template_file: String do
if is_root then return wiki.config.template_file
- return parent.template_file
+ return parent.as(not null).template_file
end
# Header template file for `self`.
# Behave like `template_file`.
fun header_file: String do
if is_root then return wiki.config.header_file
- return parent.header_file
+ return parent.as(not null).header_file
end
# Footer template file for `self`.
# Behave like `template_file`.
fun footer_file: String do
if is_root then return wiki.config.footer_file
- return parent.footer_file
+ return parent.as(not null).footer_file
end
# Menu template file for `self`.
# Behave like `template_file`.
fun menu_file: String do
if is_root then return wiki.config.menu_file
- return parent.menu_file
+ return parent.as(not null).menu_file
end
# Display the entry `name`.
redef fun title do
if has_config then
- var title = config.title
+ var title = config.as(not null).title
if title != null then return title
end
return super
#
# Hidden section are rendered but not linked in menus.
fun is_hidden: Bool do
- if has_config then return config.is_hidden
+ if has_config then return config.as(not null).is_hidden
return false
end
if parent == null then
return wiki.config.source_dir
else
- return wiki.expand_path(parent.src_path, name)
+ return wiki.expand_path(parent.as(not null).src_path, name)
end
end
# Also check custom config.
redef fun template_file do
if has_config then
- var tpl = config.template_file
+ var tpl = config.as(not null).template_file
if tpl != null then return tpl
end
if is_root then return wiki.config.template_file
- return parent.template_file
+ return parent.as(not null).template_file
end
# Also check custom config.
redef fun header_file do
if has_config then
- var tpl = config.header_file
+ var tpl = config.as(not null).header_file
if tpl != null then return tpl
end
if is_root then return wiki.config.header_file
- return parent.header_file
+ return parent.as(not null).header_file
end
# Also check custom config.
redef fun footer_file do
if has_config then
- var tpl = config.footer_file
+ var tpl = config.as(not null).footer_file
if tpl != null then return tpl
end
if is_root then return wiki.config.footer_file
- return parent.footer_file
+ return parent.as(not null).footer_file
end
# Also check custom config.
redef fun menu_file do
if has_config then
- var tpl = config.menu_file
+ var tpl = config.as(not null).menu_file
if tpl != null then return tpl
end
if is_root then return wiki.config.menu_file
- return parent.menu_file
+ return parent.as(not null).menu_file
end
end
# Articles can only have `WikiSection` as parents.
redef type PARENT: WikiSection
- redef fun title: String do
+ redef fun title do
+ var parent = self.parent
if name == "index" and parent != null then return parent.title
return super
end
content = md
end
- redef var src_full_path: nullable String = null
+ redef var src_full_path = null
redef fun src_path do
var src_full_path = self.src_full_path
# REQUIRE: `has_source`.
var md: nullable String is lazy do
if not has_source then return null
- var file = new FileReader.open(src_full_path.to_s)
+ var file = new FileReader.open(src_full_path.as(not null))
var md = file.read_all
file.close
return md
redef fun is_dirty do
if super then return true
if has_source then
- return wiki.need_render(src_full_path.to_s, out_full_path)
+ return wiki.need_render(src_full_path.as(not null), out_full_path)
end
return false
end
var sidebar_blocks: Array[String] is lazy do
var res = new Array[String]
if not has_key("wiki.sidebar.blocks") then return res
- for val in at("wiki.sidebar.blocks").values do
+ for val in at("wiki.sidebar.blocks").as(not null).values do
res.add val
end
return res
# Letters that follow a letter are lowercased
# Letters that follow a non-letter are upcased.
#
+ # If `keep_upper = true`, already uppercase letters are not lowercased.
+ #
# SEE : `Char::is_letter` for the definition of letter.
#
# assert "jAVASCRIPT".capitalized == "Javascript"
# assert "i am root".capitalized == "I Am Root"
# assert "ab_c -ab0c ab\nc".capitalized == "Ab_C -Ab0C Ab\nC"
- fun capitalized: SELFTYPE do
+ # assert "preserve my ACRONYMS".capitalized(keep_upper=true) == "Preserve My ACRONYMS"
+ fun capitalized(keep_upper: nullable Bool): SELFTYPE do
if length == 0 then return self
var buf = new Buffer.with_cap(length)
-
- var curr = chars[0].to_upper
- var prev = curr
- buf[0] = curr
-
- for i in [1 .. length[ do
- prev = curr
- curr = self[i]
- if prev.is_letter then
- buf[i] = curr.to_lower
- else
- buf[i] = curr.to_upper
- end
- end
-
+ buf.capitalize(keep_upper=keep_upper, src=self)
return buf.to_s
end
end
# Letters that follow a letter are lowercased
# Letters that follow a non-letter are upcased.
#
+ # If `keep_upper = true`, uppercase letters are not lowercased.
+ #
+ # When `src` is specified, this method reads from `src` instead of `self`
+ # but it still writes the result to the beginning of `self`.
+ # This requires `self` to have the capacity to receive all of the
+ # capitalized content of `src`.
+ #
# SEE: `Char::is_letter` for the definition of a letter.
#
# var b = new FlatBuffer.from("jAVAsCriPt")
# b = new FlatBuffer.from("ab_c -ab0c ab\nc")
# b.capitalize
# assert b == "Ab_C -Ab0C Ab\nC"
- fun capitalize do
+ #
+ # b = new FlatBuffer.from("12345")
+ # b.capitalize(src="foo")
+ # assert b == "Foo45"
+ #
+ # b = new FlatBuffer.from("preserve my ACRONYMS")
+ # b.capitalize(keep_upper=true)
+ # assert b == "Preserve My ACRONYMS"
+ fun capitalize(keep_upper: nullable Bool, src: nullable Text) do
+ src = src or else self
+ var length = src.length
if length == 0 then return
- var c = self[0].to_upper
+ keep_upper = keep_upper or else false
+
+ var c = src[0].to_upper
self[0] = c
var prev = c
for i in [1 .. length[ do
prev = c
- c = self[i]
+ c = src[i]
if prev.is_letter then
- self[i] = c.to_lower
+ if keep_upper then
+ self[i] = c
+ else
+ self[i] = c.to_lower
+ end
else
self[i] = c.to_upper
end
# see `alpha_comparator`
private class AlphaComparator
super Comparator
- redef fun compare(a, b) do return a.to_s <=> b.to_s
+ redef fun compare(a, b) do
+ if a == b then return 0
+ if a == null then return -1
+ if b == null then return 1
+ return a.to_s <=> b.to_s
+ end
end
# Stateless comparator that naively use `to_s` to compare things.
# SEE: `abstract_text::Text` for more info on the difference
# between `Text::bytelen` and `Text::length`.
fun to_s_full(bytelen, unilen: Int): String is abstract
+
+ # Copies the content of `src` to `self`
+ #
+ # NOTE: `self` must be large enough to withold `self.bytelen` bytes
+ fun fill_from(src: Text) do src.copy_to_native(self, src.bytelen, 0, 0)
end
redef class NativeArray[E]