org-ruby 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.bnsignore +18 -0
- data/History.txt +40 -32
- data/README.txt +66 -66
- data/Rakefile +27 -26
- data/bin/org-ruby +40 -40
- data/lib/org-ruby.rb +50 -50
- data/lib/org-ruby/headline.rb +80 -75
- data/lib/org-ruby/html_output_buffer.rb +105 -81
- data/lib/org-ruby/line.rb +173 -173
- data/lib/org-ruby/output_buffer.rb +172 -154
- data/lib/org-ruby/parser.rb +80 -76
- data/lib/org-ruby/regexp_helper.rb +156 -156
- data/lib/org-ruby/textile_output_buffer.rb +67 -67
- data/spec/data/freeform.org +111 -111
- data/spec/data/hyp-planning.org +335 -335
- data/spec/data/remember.org +53 -53
- data/spec/headline_spec.rb +55 -55
- data/spec/html_examples/advanced-lists.html +31 -0
- data/spec/html_examples/advanced-lists.org +31 -0
- data/spec/html_examples/block_code.html +30 -30
- data/spec/html_examples/block_code.org +35 -35
- data/spec/html_examples/blockquote.html +7 -7
- data/spec/html_examples/blockquote.org +13 -13
- data/spec/html_examples/escape-pre.html +7 -7
- data/spec/html_examples/escape-pre.org +6 -6
- data/spec/html_examples/inline-formatting.html +10 -10
- data/spec/html_examples/inline-formatting.org +17 -17
- data/spec/html_examples/lists.html +19 -19
- data/spec/html_examples/lists.org +36 -36
- data/spec/html_examples/only-list.html +5 -5
- data/spec/html_examples/only-list.org +3 -3
- data/spec/html_examples/only-table.html +6 -6
- data/spec/html_examples/only-table.org +5 -5
- data/spec/html_examples/tables.html +20 -20
- data/spec/html_examples/tables.org +26 -26
- data/spec/html_examples/text.html +2 -2
- data/spec/html_examples/text.org +16 -16
- data/spec/line_spec.rb +89 -89
- data/spec/parser_spec.rb +86 -86
- data/spec/regexp_helper_spec.rb +57 -57
- data/spec/spec_helper.rb +20 -20
- data/spec/textile_examples/block_code.org +35 -35
- data/spec/textile_examples/block_code.textile +29 -29
- data/spec/textile_examples/blockquote.org +13 -13
- data/spec/textile_examples/blockquote.textile +11 -11
- data/spec/textile_examples/keywords.org +13 -13
- data/spec/textile_examples/keywords.textile +11 -11
- data/spec/textile_examples/links.org +11 -11
- data/spec/textile_examples/links.textile +10 -10
- data/spec/textile_examples/lists.org +36 -36
- data/spec/textile_examples/lists.textile +20 -20
- data/spec/textile_examples/single-space-plain-list.org +13 -13
- data/spec/textile_examples/single-space-plain-list.textile +10 -10
- data/spec/textile_examples/tables.org +26 -26
- data/spec/textile_examples/tables.textile +23 -23
- data/spec/textile_output_buffer_spec.rb +21 -21
- data/tasks/test_case.rake +49 -49
- metadata +5 -2
@@ -1,156 +1,156 @@
|
|
1
|
-
require 'logger'
|
2
|
-
|
3
|
-
module Orgmode
|
4
|
-
|
5
|
-
# = Summary
|
6
|
-
#
|
7
|
-
# This class contains helper routines to deal with the Regexp "black
|
8
|
-
# magic" you need to properly parse org-mode files.
|
9
|
-
#
|
10
|
-
# = Key methods
|
11
|
-
#
|
12
|
-
# * Use +rewrite_emphasis+ to replace org-mode emphasis strings (e.g.,
|
13
|
-
# \/italic/) with the suitable markup for the output.
|
14
|
-
#
|
15
|
-
# * Use +rewrite_links+ to get a chance to rewrite all org-mode
|
16
|
-
# links with suitable markup for the output.
|
17
|
-
class RegexpHelper
|
18
|
-
|
19
|
-
######################################################################
|
20
|
-
# EMPHASIS
|
21
|
-
#
|
22
|
-
# I figure it's best to stick as closely to the elisp implementation
|
23
|
-
# as possible for emphasis. org.el defines the regular expression that
|
24
|
-
# is used to apply "emphasis" (in my terminology, inline formatting
|
25
|
-
# instead of block formatting). Here's the documentation from org.el.
|
26
|
-
#
|
27
|
-
# Terminology: In an emphasis string like " *strong word* ", we
|
28
|
-
# call the initial space PREMATCH, the final space POSTMATCH, the
|
29
|
-
# stars MARKERS, "s" and "d" are BORDER characters and "trong wor"
|
30
|
-
# is the body. The different components in this variable specify
|
31
|
-
# what is allowed/forbidden in each part:
|
32
|
-
#
|
33
|
-
# pre Chars allowed as prematch. Line beginning allowed, too.
|
34
|
-
# post Chars allowed as postmatch. Line end will be allowed too.
|
35
|
-
# border The chars *forbidden* as border characters.
|
36
|
-
# body-regexp A regexp like \".\" to match a body character. Don't use
|
37
|
-
# non-shy groups here, and don't allow newline here.
|
38
|
-
# newline The maximum number of newlines allowed in an emphasis exp.
|
39
|
-
#
|
40
|
-
# I currently don't use +newline+ because I've thrown this information
|
41
|
-
# away by this point in the code. TODO -- revisit?
|
42
|
-
attr_reader :pre_emphasis
|
43
|
-
attr_reader :post_emphasis
|
44
|
-
attr_reader :border_forbidden
|
45
|
-
attr_reader :body_regexp
|
46
|
-
attr_reader :markers
|
47
|
-
|
48
|
-
attr_reader :org_emphasis_regexp
|
49
|
-
|
50
|
-
def initialize
|
51
|
-
# Set up the emphasis regular expression.
|
52
|
-
@pre_emphasis = " \t\\('\""
|
53
|
-
@post_emphasis = "- \t.,:!?;'\"\\)"
|
54
|
-
@border_forbidden = " \t\r\n,\"'"
|
55
|
-
@body_regexp = ".*?"
|
56
|
-
@markers = "*/_=~+"
|
57
|
-
@logger = Logger.new(STDERR)
|
58
|
-
@logger.level = Logger::WARN
|
59
|
-
build_org_emphasis_regexp
|
60
|
-
build_org_link_regexp
|
61
|
-
end
|
62
|
-
|
63
|
-
# Finds all emphasis matches in a string.
|
64
|
-
# Supply a block that will get the marker and body as parameters.
|
65
|
-
def match_all(str)
|
66
|
-
str.scan(@org_emphasis_regexp) do |match|
|
67
|
-
yield $2, $3
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
# Compute replacements for all matching emphasized phrases.
|
72
|
-
# Supply a block that will get the marker and body as parameters;
|
73
|
-
# return the replacement string from your block.
|
74
|
-
#
|
75
|
-
# = Example
|
76
|
-
#
|
77
|
-
# re = RegexpHelper.new
|
78
|
-
# result = re.rewrite_emphasis("*bold*, /italic/, =code=") do |marker, body|
|
79
|
-
# "<#{map[marker]}>#{body}</#{map[marker]}>"
|
80
|
-
# end
|
81
|
-
#
|
82
|
-
# In this example, the block body will get called three times:
|
83
|
-
#
|
84
|
-
# 1. Marker: "*", body: "bold"
|
85
|
-
# 2. Marker: "/", body: "italic"
|
86
|
-
# 3. Marker: "=", body: "code"
|
87
|
-
#
|
88
|
-
# The return from this block is a string that will be used to
|
89
|
-
# replace "*bold*", "/italic/", and "=code=",
|
90
|
-
# respectively. (Clearly this sample string will use HTML-like
|
91
|
-
# syntax, assuming +map+ is defined appropriately.)
|
92
|
-
def rewrite_emphasis(str)
|
93
|
-
str.gsub(@org_emphasis_regexp) do |match|
|
94
|
-
inner = yield $2, $3
|
95
|
-
"#{$1}#{inner}#{$4}"
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
# = Summary
|
100
|
-
#
|
101
|
-
# Rewrite org-mode links in a string to markup suitable to the
|
102
|
-
# output format.
|
103
|
-
#
|
104
|
-
# = Usage
|
105
|
-
#
|
106
|
-
# Give this a block that expect the link and optional friendly
|
107
|
-
# text. Return how that link should get formatted.
|
108
|
-
#
|
109
|
-
# = Example
|
110
|
-
#
|
111
|
-
# re = RegexpHelper.new
|
112
|
-
# result = re.rewrite_links("[[http://www.bing.com]] and [[http://www.hotmail.com][Hotmail]]") do |link, text}
|
113
|
-
# text ||= link
|
114
|
-
# "<a href=\"#{link}\">#{text}</a>"
|
115
|
-
# end
|
116
|
-
#
|
117
|
-
# In this example, the block body will get called two times. In the
|
118
|
-
# first instance, +text+ will be nil (the org-mode markup gives no
|
119
|
-
# friendly text for the link +http://www.bing.com+. In the second
|
120
|
-
# instance, the block will get text of *Hotmail* and the link
|
121
|
-
# +http://www.hotmail.com+. In both cases, the block returns an
|
122
|
-
# HTML-style link, and that is how things will get recorded in
|
123
|
-
# +result+.
|
124
|
-
def rewrite_links(str)
|
125
|
-
i = str.gsub(@org_link_regexp) do |match|
|
126
|
-
yield $1, nil
|
127
|
-
end
|
128
|
-
i.gsub(@org_link_text_regexp) do |match|
|
129
|
-
yield $1, $2
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
private
|
134
|
-
|
135
|
-
def build_org_emphasis_regexp
|
136
|
-
@org_emphasis_regexp = Regexp.new("([#{@pre_emphasis}]|^)\n" +
|
137
|
-
"( [#{@markers}] )\n" +
|
138
|
-
"( [^#{@border_forbidden}] | " +
|
139
|
-
" [^#{@border_forbidden}]#{@body_regexp}[^#{@border_forbidden}] )\n" +
|
140
|
-
"\\2\n" +
|
141
|
-
"([#{@post_emphasis}]|$)\n", Regexp::EXTENDED)
|
142
|
-
@logger.debug "Just created regexp: #{@org_emphasis_regexp}"
|
143
|
-
end
|
144
|
-
|
145
|
-
def build_org_link_regexp
|
146
|
-
@org_link_regexp = /\[\[
|
147
|
-
([^\]]*) # This is the URL
|
148
|
-
\]\]/x
|
149
|
-
@org_link_text_regexp = /\[\[
|
150
|
-
([^\]]*) # This is the URL
|
151
|
-
\]\[
|
152
|
-
([^\]]*) # This is the friendly text
|
153
|
-
\]\]/x
|
154
|
-
end
|
155
|
-
end # class Emphasis
|
156
|
-
end # module Orgmode
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Orgmode
|
4
|
+
|
5
|
+
# = Summary
|
6
|
+
#
|
7
|
+
# This class contains helper routines to deal with the Regexp "black
|
8
|
+
# magic" you need to properly parse org-mode files.
|
9
|
+
#
|
10
|
+
# = Key methods
|
11
|
+
#
|
12
|
+
# * Use +rewrite_emphasis+ to replace org-mode emphasis strings (e.g.,
|
13
|
+
# \/italic/) with the suitable markup for the output.
|
14
|
+
#
|
15
|
+
# * Use +rewrite_links+ to get a chance to rewrite all org-mode
|
16
|
+
# links with suitable markup for the output.
|
17
|
+
class RegexpHelper
|
18
|
+
|
19
|
+
######################################################################
|
20
|
+
# EMPHASIS
|
21
|
+
#
|
22
|
+
# I figure it's best to stick as closely to the elisp implementation
|
23
|
+
# as possible for emphasis. org.el defines the regular expression that
|
24
|
+
# is used to apply "emphasis" (in my terminology, inline formatting
|
25
|
+
# instead of block formatting). Here's the documentation from org.el.
|
26
|
+
#
|
27
|
+
# Terminology: In an emphasis string like " *strong word* ", we
|
28
|
+
# call the initial space PREMATCH, the final space POSTMATCH, the
|
29
|
+
# stars MARKERS, "s" and "d" are BORDER characters and "trong wor"
|
30
|
+
# is the body. The different components in this variable specify
|
31
|
+
# what is allowed/forbidden in each part:
|
32
|
+
#
|
33
|
+
# pre Chars allowed as prematch. Line beginning allowed, too.
|
34
|
+
# post Chars allowed as postmatch. Line end will be allowed too.
|
35
|
+
# border The chars *forbidden* as border characters.
|
36
|
+
# body-regexp A regexp like \".\" to match a body character. Don't use
|
37
|
+
# non-shy groups here, and don't allow newline here.
|
38
|
+
# newline The maximum number of newlines allowed in an emphasis exp.
|
39
|
+
#
|
40
|
+
# I currently don't use +newline+ because I've thrown this information
|
41
|
+
# away by this point in the code. TODO -- revisit?
|
42
|
+
attr_reader :pre_emphasis
|
43
|
+
attr_reader :post_emphasis
|
44
|
+
attr_reader :border_forbidden
|
45
|
+
attr_reader :body_regexp
|
46
|
+
attr_reader :markers
|
47
|
+
|
48
|
+
attr_reader :org_emphasis_regexp
|
49
|
+
|
50
|
+
def initialize
|
51
|
+
# Set up the emphasis regular expression.
|
52
|
+
@pre_emphasis = " \t\\('\""
|
53
|
+
@post_emphasis = "- \t.,:!?;'\"\\)"
|
54
|
+
@border_forbidden = " \t\r\n,\"'"
|
55
|
+
@body_regexp = ".*?"
|
56
|
+
@markers = "*/_=~+"
|
57
|
+
@logger = Logger.new(STDERR)
|
58
|
+
@logger.level = Logger::WARN
|
59
|
+
build_org_emphasis_regexp
|
60
|
+
build_org_link_regexp
|
61
|
+
end
|
62
|
+
|
63
|
+
# Finds all emphasis matches in a string.
|
64
|
+
# Supply a block that will get the marker and body as parameters.
|
65
|
+
def match_all(str)
|
66
|
+
str.scan(@org_emphasis_regexp) do |match|
|
67
|
+
yield $2, $3
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Compute replacements for all matching emphasized phrases.
|
72
|
+
# Supply a block that will get the marker and body as parameters;
|
73
|
+
# return the replacement string from your block.
|
74
|
+
#
|
75
|
+
# = Example
|
76
|
+
#
|
77
|
+
# re = RegexpHelper.new
|
78
|
+
# result = re.rewrite_emphasis("*bold*, /italic/, =code=") do |marker, body|
|
79
|
+
# "<#{map[marker]}>#{body}</#{map[marker]}>"
|
80
|
+
# end
|
81
|
+
#
|
82
|
+
# In this example, the block body will get called three times:
|
83
|
+
#
|
84
|
+
# 1. Marker: "*", body: "bold"
|
85
|
+
# 2. Marker: "/", body: "italic"
|
86
|
+
# 3. Marker: "=", body: "code"
|
87
|
+
#
|
88
|
+
# The return from this block is a string that will be used to
|
89
|
+
# replace "*bold*", "/italic/", and "=code=",
|
90
|
+
# respectively. (Clearly this sample string will use HTML-like
|
91
|
+
# syntax, assuming +map+ is defined appropriately.)
|
92
|
+
def rewrite_emphasis(str)
|
93
|
+
str.gsub(@org_emphasis_regexp) do |match|
|
94
|
+
inner = yield $2, $3
|
95
|
+
"#{$1}#{inner}#{$4}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# = Summary
|
100
|
+
#
|
101
|
+
# Rewrite org-mode links in a string to markup suitable to the
|
102
|
+
# output format.
|
103
|
+
#
|
104
|
+
# = Usage
|
105
|
+
#
|
106
|
+
# Give this a block that expect the link and optional friendly
|
107
|
+
# text. Return how that link should get formatted.
|
108
|
+
#
|
109
|
+
# = Example
|
110
|
+
#
|
111
|
+
# re = RegexpHelper.new
|
112
|
+
# result = re.rewrite_links("[[http://www.bing.com]] and [[http://www.hotmail.com][Hotmail]]") do |link, text}
|
113
|
+
# text ||= link
|
114
|
+
# "<a href=\"#{link}\">#{text}</a>"
|
115
|
+
# end
|
116
|
+
#
|
117
|
+
# In this example, the block body will get called two times. In the
|
118
|
+
# first instance, +text+ will be nil (the org-mode markup gives no
|
119
|
+
# friendly text for the link +http://www.bing.com+. In the second
|
120
|
+
# instance, the block will get text of *Hotmail* and the link
|
121
|
+
# +http://www.hotmail.com+. In both cases, the block returns an
|
122
|
+
# HTML-style link, and that is how things will get recorded in
|
123
|
+
# +result+.
|
124
|
+
def rewrite_links(str)
|
125
|
+
i = str.gsub(@org_link_regexp) do |match|
|
126
|
+
yield $1, nil
|
127
|
+
end
|
128
|
+
i.gsub(@org_link_text_regexp) do |match|
|
129
|
+
yield $1, $2
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
def build_org_emphasis_regexp
|
136
|
+
@org_emphasis_regexp = Regexp.new("([#{@pre_emphasis}]|^)\n" +
|
137
|
+
"( [#{@markers}] )\n" +
|
138
|
+
"( [^#{@border_forbidden}] | " +
|
139
|
+
" [^#{@border_forbidden}]#{@body_regexp}[^#{@border_forbidden}] )\n" +
|
140
|
+
"\\2\n" +
|
141
|
+
"([#{@post_emphasis}]|$)\n", Regexp::EXTENDED)
|
142
|
+
@logger.debug "Just created regexp: #{@org_emphasis_regexp}"
|
143
|
+
end
|
144
|
+
|
145
|
+
def build_org_link_regexp
|
146
|
+
@org_link_regexp = /\[\[
|
147
|
+
([^\]]*) # This is the URL
|
148
|
+
\]\]/x
|
149
|
+
@org_link_text_regexp = /\[\[
|
150
|
+
([^\]]*) # This is the URL
|
151
|
+
\]\[
|
152
|
+
([^\]]*) # This is the friendly text
|
153
|
+
\]\]/x
|
154
|
+
end
|
155
|
+
end # class Emphasis
|
156
|
+
end # module Orgmode
|
@@ -1,67 +1,67 @@
|
|
1
|
-
require 'stringio'
|
2
|
-
|
3
|
-
module Orgmode
|
4
|
-
|
5
|
-
class TextileOutputBuffer < OutputBuffer
|
6
|
-
|
7
|
-
def initialize(output)
|
8
|
-
super(output)
|
9
|
-
@add_paragraph = false
|
10
|
-
end
|
11
|
-
|
12
|
-
def push_mode(mode)
|
13
|
-
super(mode)
|
14
|
-
@output << "bc.. " if mode == :code
|
15
|
-
end
|
16
|
-
|
17
|
-
def pop_mode(mode = nil)
|
18
|
-
m = super(mode)
|
19
|
-
@add_paragraph = (m == :code)
|
20
|
-
m
|
21
|
-
end
|
22
|
-
|
23
|
-
# Maps org markup to textile markup.
|
24
|
-
TextileMap = {
|
25
|
-
"*" => "*",
|
26
|
-
"/" => "_",
|
27
|
-
"_" => "_",
|
28
|
-
"=" => "@",
|
29
|
-
"~" => "@",
|
30
|
-
"+" => "+"
|
31
|
-
}
|
32
|
-
|
33
|
-
# Handles inline formatting for textile.
|
34
|
-
def inline_formatting(input)
|
35
|
-
input = @re_help.rewrite_emphasis(input) do |marker, body|
|
36
|
-
m = TextileMap[marker]
|
37
|
-
"#{m}#{body}#{m}"
|
38
|
-
end
|
39
|
-
input = @re_help.rewrite_links(input) do |link, text|
|
40
|
-
text ||= link
|
41
|
-
link = link.gsub(/ /, "%20")
|
42
|
-
"\"#{text}\":#{link}"
|
43
|
-
end
|
44
|
-
input
|
45
|
-
end
|
46
|
-
|
47
|
-
# Flushes the current buffer
|
48
|
-
def flush!
|
49
|
-
@logger.debug "FLUSH ==========> #{@output_type}"
|
50
|
-
if (@output_type == :blank) then
|
51
|
-
@output << "\n"
|
52
|
-
elsif (@buffer.length > 0) then
|
53
|
-
if @add_paragraph then
|
54
|
-
@output << "p. " if @output_type == :paragraph
|
55
|
-
@add_paragraph = false
|
56
|
-
end
|
57
|
-
@output << "bq. " if current_mode == :blockquote
|
58
|
-
@output << "#" * @list_indent_stack.length << " " if @output_type == :ordered_list
|
59
|
-
@output << "*" * @list_indent_stack.length << " " if @output_type == :unordered_list
|
60
|
-
@output << inline_formatting(@buffer) << "\n"
|
61
|
-
end
|
62
|
-
@buffer = ""
|
63
|
-
end
|
64
|
-
|
65
|
-
|
66
|
-
end # class TextileOutputBuffer
|
67
|
-
end # module Orgmode
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
module Orgmode
|
4
|
+
|
5
|
+
class TextileOutputBuffer < OutputBuffer
|
6
|
+
|
7
|
+
def initialize(output)
|
8
|
+
super(output)
|
9
|
+
@add_paragraph = false
|
10
|
+
end
|
11
|
+
|
12
|
+
def push_mode(mode)
|
13
|
+
super(mode)
|
14
|
+
@output << "bc.. " if mode == :code
|
15
|
+
end
|
16
|
+
|
17
|
+
def pop_mode(mode = nil)
|
18
|
+
m = super(mode)
|
19
|
+
@add_paragraph = (m == :code)
|
20
|
+
m
|
21
|
+
end
|
22
|
+
|
23
|
+
# Maps org markup to textile markup.
|
24
|
+
TextileMap = {
|
25
|
+
"*" => "*",
|
26
|
+
"/" => "_",
|
27
|
+
"_" => "_",
|
28
|
+
"=" => "@",
|
29
|
+
"~" => "@",
|
30
|
+
"+" => "+"
|
31
|
+
}
|
32
|
+
|
33
|
+
# Handles inline formatting for textile.
|
34
|
+
def inline_formatting(input)
|
35
|
+
input = @re_help.rewrite_emphasis(input) do |marker, body|
|
36
|
+
m = TextileMap[marker]
|
37
|
+
"#{m}#{body}#{m}"
|
38
|
+
end
|
39
|
+
input = @re_help.rewrite_links(input) do |link, text|
|
40
|
+
text ||= link
|
41
|
+
link = link.gsub(/ /, "%20")
|
42
|
+
"\"#{text}\":#{link}"
|
43
|
+
end
|
44
|
+
input
|
45
|
+
end
|
46
|
+
|
47
|
+
# Flushes the current buffer
|
48
|
+
def flush!
|
49
|
+
@logger.debug "FLUSH ==========> #{@output_type}"
|
50
|
+
if (@output_type == :blank) then
|
51
|
+
@output << "\n"
|
52
|
+
elsif (@buffer.length > 0) then
|
53
|
+
if @add_paragraph then
|
54
|
+
@output << "p. " if @output_type == :paragraph
|
55
|
+
@add_paragraph = false
|
56
|
+
end
|
57
|
+
@output << "bq. " if current_mode == :blockquote
|
58
|
+
@output << "#" * @list_indent_stack.length << " " if @output_type == :ordered_list
|
59
|
+
@output << "*" * @list_indent_stack.length << " " if @output_type == :unordered_list
|
60
|
+
@output << inline_formatting(@buffer) << "\n"
|
61
|
+
end
|
62
|
+
@buffer = ""
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
end # class TextileOutputBuffer
|
67
|
+
end # module Orgmode
|
data/spec/data/freeform.org
CHANGED
@@ -1,111 +1,111 @@
|
|
1
|
-
#+TITLE: Freeform
|
2
|
-
#+AUTHOR:
|
3
|
-
#+EMAIL: bdewey@gmail.com
|
4
|
-
#+DATE: 2009-12-20 Sun
|
5
|
-
#+DESCRIPTION:
|
6
|
-
#+KEYWORDS:
|
7
|
-
#+LANGUAGE: en
|
8
|
-
#+OPTIONS: H:3 num:t toc:nil \n:nil @:t ::t |:t ^:t -:t f:t *:t <:t
|
9
|
-
#+OPTIONS: TeX:t LaTeX:nil skip:nil d:nil todo:t pri:nil tags:not-in-toc
|
10
|
-
#+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js
|
11
|
-
#+EXPORT_SELECT_TAGS: export
|
12
|
-
#+EXPORT_EXCLUDE_TAGS: noexport
|
13
|
-
#+LINK_UP:
|
14
|
-
#+LINK_HOME:
|
15
|
-
Freeform
|
16
|
-
|
17
|
-
This is my todo list, research file, and log record from working on
|
18
|
-
the Freeform project.
|
19
|
-
|
20
|
-
* Future ideas :someday:
|
21
|
-
- Add *posts*
|
22
|
-
- Enforce uniqueness of url_token
|
23
|
-
- Add FeedSync support
|
24
|
-
- Auto-recognize URLs
|
25
|
-
- Edit in place
|
26
|
-
- Import/export of content. I want it to be safe to store real content on the site.
|
27
|
-
- Page reordering.
|
28
|
-
- AtomPub support.
|
29
|
-
- Organization:
|
30
|
-
- Move pages around
|
31
|
-
- Add tags and navigation by tags
|
32
|
-
- Add a breadcrumb bar
|
33
|
-
|
34
|
-
* TODO Add versioning support :current:feature:
|
35
|
-
|
36
|
-
** DONE UI rough-in
|
37
|
-
CLOSED: [2009-11-26 Thu]
|
38
|
-
|
39
|
-
** DONE Author logging
|
40
|
-
CLOSED: [2009-11-27 Fri]
|
41
|
-
|
42
|
-
** DONE Version table and model updates
|
43
|
-
CLOSED: [2009-11-28 Sat 22:40]
|
44
|
-
CLOCK: [2009-11-28 Sat 21:35]--[2009-11-28 Sat 22:40] => 1:05
|
45
|
-
CLOCK: [2009-11-28 Sat 21:01]--[2009-11-28 Sat 21:25] => 0:24
|
46
|
-
CLOCK: [2009-11-28 Sat 19:46]--[2009-11-28 Sat 20:54] => 1:08
|
47
|
-
CLOCK: [2009-11-28 Sat 14:38]--[2009-11-28 Sat 15:08] => 0:30
|
48
|
-
CLOCK: [2009-11-28 Sat 13:21]--[2009-11-28 Sat 14:37] => 1:16
|
49
|
-
|
50
|
-
OK, my current thinking is to have each idea have many Changes. A
|
51
|
-
change has many change records. A change record is a list of
|
52
|
-
specific attributes that change, and includes the old and the new
|
53
|
-
values. I'll use callbacks on the Idea model to maintain the
|
54
|
-
changes.
|
55
|
-
|
56
|
-
|
57
|
-
*** DONE Create version method
|
58
|
-
CLOSED: [2009-11-28 Sat 22:40]
|
59
|
-
|
60
|
-
*** DONE Make current method
|
61
|
-
CLOSED: [2009-11-28 Sat 22:40]
|
62
|
-
|
63
|
-
** Update pages controller
|
64
|
-
|
65
|
-
*** DONE Show versions
|
66
|
-
CLOSED: [2009-11-30 Mon 00:34]
|
67
|
-
CLOCK: [2009-11-29 Sun 21:27]--[2009-11-29 Sun 21:54] => 0:27
|
68
|
-
CLOCK: [2009-11-29 Sun 15:40]--[2009-11-29 Sun 15:44] => 0:04
|
69
|
-
CLOCK: [2009-11-28 Sat 22:44]--[2009-11-28 Sat 23:50] => 1:06
|
70
|
-
|
71
|
-
I'm now at the point where I *list* versions, but I can't show
|
72
|
-
them.
|
73
|
-
|
74
|
-
- [X] I currently suspect that I broke my version recovery code
|
75
|
-
when I switched the order of the idea_changes. I need to
|
76
|
-
investigate why nothing's failing in the tests; I expected
|
77
|
-
failures. Possible addition to test: start looking at those
|
78
|
-
version numbers.
|
79
|
-
|
80
|
-
OK, here's what was going on: In the test, you need to
|
81
|
-
reload the idea_changes array from the database to get the
|
82
|
-
database sort order. I also make sure I do this inside the
|
83
|
-
Idea methods.
|
84
|
-
|
85
|
-
**** DONE Write a test for Idea::attributes_for_change
|
86
|
-
CLOSED: [2009-11-29 Sun 23:59]
|
87
|
-
CLOCK: [2009-11-29 Sun 23:47]--[2009-11-29 Sun 23:58] => 0:11
|
88
|
-
CLOCK: [2009-11-29 Sun 22:02]--[2009-11-29 Sun 23:42] => 1:40
|
89
|
-
CLOCK: [2009-11-29 Sun 21:54]--[2009-11-29 Sun 21:56] => 0:02
|
90
|
-
|
91
|
-
*** DONE Write integration tests that cover versions.
|
92
|
-
CLOSED: [2009-12-11 Fri 23:25]
|
93
|
-
CLOCK: [2009-12-11 Fri 20:27]--[2009-12-11 Fri 23:25] => 2:58
|
94
|
-
|
95
|
-
*** DONE Recover versions
|
96
|
-
CLOSED: [2009-12-12 Sat 22:09]
|
97
|
-
CLOCK: [2009-12-12 Sat 21:02]--[2009-12-12 Sat 22:09] => 1:07
|
98
|
-
CLOCK: [2009-12-12 Sat 20:13]--[2009-12-12 Sat 21:00] => 0:47
|
99
|
-
|
100
|
-
*** DONE Move to recycle bin
|
101
|
-
CLOSED: [2009-12-12 Sat 22:59]
|
102
|
-
CLOCK: [2009-12-12 Sat 22:23]--[2009-12-12 Sat 22:59] => 0:36
|
103
|
-
|
104
|
-
Note I'm avoiding logging delete operations because I'm presuming
|
105
|
-
there will be a recycle bin, and therefore the *pages* controller
|
106
|
-
will never actually delete files. At some point, when I want to
|
107
|
-
support full FeedSync, I'll need to tackle this.
|
108
|
-
|
109
|
-
The other timebomb: I don't know how well my logging scheme will
|
110
|
-
work when pages move. I don't yet know if I will address this in
|
111
|
-
the current sprint.
|
1
|
+
#+TITLE: Freeform
|
2
|
+
#+AUTHOR:
|
3
|
+
#+EMAIL: bdewey@gmail.com
|
4
|
+
#+DATE: 2009-12-20 Sun
|
5
|
+
#+DESCRIPTION:
|
6
|
+
#+KEYWORDS:
|
7
|
+
#+LANGUAGE: en
|
8
|
+
#+OPTIONS: H:3 num:t toc:nil \n:nil @:t ::t |:t ^:t -:t f:t *:t <:t
|
9
|
+
#+OPTIONS: TeX:t LaTeX:nil skip:nil d:nil todo:t pri:nil tags:not-in-toc
|
10
|
+
#+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js
|
11
|
+
#+EXPORT_SELECT_TAGS: export
|
12
|
+
#+EXPORT_EXCLUDE_TAGS: noexport
|
13
|
+
#+LINK_UP:
|
14
|
+
#+LINK_HOME:
|
15
|
+
Freeform
|
16
|
+
|
17
|
+
This is my todo list, research file, and log record from working on
|
18
|
+
the Freeform project.
|
19
|
+
|
20
|
+
* Future ideas :someday:
|
21
|
+
- Add *posts*
|
22
|
+
- Enforce uniqueness of url_token
|
23
|
+
- Add FeedSync support
|
24
|
+
- Auto-recognize URLs
|
25
|
+
- Edit in place
|
26
|
+
- Import/export of content. I want it to be safe to store real content on the site.
|
27
|
+
- Page reordering.
|
28
|
+
- AtomPub support.
|
29
|
+
- Organization:
|
30
|
+
- Move pages around
|
31
|
+
- Add tags and navigation by tags
|
32
|
+
- Add a breadcrumb bar
|
33
|
+
|
34
|
+
* TODO Add versioning support :current:feature:
|
35
|
+
|
36
|
+
** DONE UI rough-in
|
37
|
+
CLOSED: [2009-11-26 Thu]
|
38
|
+
|
39
|
+
** DONE Author logging
|
40
|
+
CLOSED: [2009-11-27 Fri]
|
41
|
+
|
42
|
+
** DONE Version table and model updates
|
43
|
+
CLOSED: [2009-11-28 Sat 22:40]
|
44
|
+
CLOCK: [2009-11-28 Sat 21:35]--[2009-11-28 Sat 22:40] => 1:05
|
45
|
+
CLOCK: [2009-11-28 Sat 21:01]--[2009-11-28 Sat 21:25] => 0:24
|
46
|
+
CLOCK: [2009-11-28 Sat 19:46]--[2009-11-28 Sat 20:54] => 1:08
|
47
|
+
CLOCK: [2009-11-28 Sat 14:38]--[2009-11-28 Sat 15:08] => 0:30
|
48
|
+
CLOCK: [2009-11-28 Sat 13:21]--[2009-11-28 Sat 14:37] => 1:16
|
49
|
+
|
50
|
+
OK, my current thinking is to have each idea have many Changes. A
|
51
|
+
change has many change records. A change record is a list of
|
52
|
+
specific attributes that change, and includes the old and the new
|
53
|
+
values. I'll use callbacks on the Idea model to maintain the
|
54
|
+
changes.
|
55
|
+
|
56
|
+
|
57
|
+
*** DONE Create version method
|
58
|
+
CLOSED: [2009-11-28 Sat 22:40]
|
59
|
+
|
60
|
+
*** DONE Make current method
|
61
|
+
CLOSED: [2009-11-28 Sat 22:40]
|
62
|
+
|
63
|
+
** Update pages controller
|
64
|
+
|
65
|
+
*** DONE Show versions
|
66
|
+
CLOSED: [2009-11-30 Mon 00:34]
|
67
|
+
CLOCK: [2009-11-29 Sun 21:27]--[2009-11-29 Sun 21:54] => 0:27
|
68
|
+
CLOCK: [2009-11-29 Sun 15:40]--[2009-11-29 Sun 15:44] => 0:04
|
69
|
+
CLOCK: [2009-11-28 Sat 22:44]--[2009-11-28 Sat 23:50] => 1:06
|
70
|
+
|
71
|
+
I'm now at the point where I *list* versions, but I can't show
|
72
|
+
them.
|
73
|
+
|
74
|
+
- [X] I currently suspect that I broke my version recovery code
|
75
|
+
when I switched the order of the idea_changes. I need to
|
76
|
+
investigate why nothing's failing in the tests; I expected
|
77
|
+
failures. Possible addition to test: start looking at those
|
78
|
+
version numbers.
|
79
|
+
|
80
|
+
OK, here's what was going on: In the test, you need to
|
81
|
+
reload the idea_changes array from the database to get the
|
82
|
+
database sort order. I also make sure I do this inside the
|
83
|
+
Idea methods.
|
84
|
+
|
85
|
+
**** DONE Write a test for Idea::attributes_for_change
|
86
|
+
CLOSED: [2009-11-29 Sun 23:59]
|
87
|
+
CLOCK: [2009-11-29 Sun 23:47]--[2009-11-29 Sun 23:58] => 0:11
|
88
|
+
CLOCK: [2009-11-29 Sun 22:02]--[2009-11-29 Sun 23:42] => 1:40
|
89
|
+
CLOCK: [2009-11-29 Sun 21:54]--[2009-11-29 Sun 21:56] => 0:02
|
90
|
+
|
91
|
+
*** DONE Write integration tests that cover versions.
|
92
|
+
CLOSED: [2009-12-11 Fri 23:25]
|
93
|
+
CLOCK: [2009-12-11 Fri 20:27]--[2009-12-11 Fri 23:25] => 2:58
|
94
|
+
|
95
|
+
*** DONE Recover versions
|
96
|
+
CLOSED: [2009-12-12 Sat 22:09]
|
97
|
+
CLOCK: [2009-12-12 Sat 21:02]--[2009-12-12 Sat 22:09] => 1:07
|
98
|
+
CLOCK: [2009-12-12 Sat 20:13]--[2009-12-12 Sat 21:00] => 0:47
|
99
|
+
|
100
|
+
*** DONE Move to recycle bin
|
101
|
+
CLOSED: [2009-12-12 Sat 22:59]
|
102
|
+
CLOCK: [2009-12-12 Sat 22:23]--[2009-12-12 Sat 22:59] => 0:36
|
103
|
+
|
104
|
+
Note I'm avoiding logging delete operations because I'm presuming
|
105
|
+
there will be a recycle bin, and therefore the *pages* controller
|
106
|
+
will never actually delete files. At some point, when I want to
|
107
|
+
support full FeedSync, I'll need to tackle this.
|
108
|
+
|
109
|
+
The other timebomb: I don't know how well my logging scheme will
|
110
|
+
work when pages move. I don't yet know if I will address this in
|
111
|
+
the current sprint.
|