org-ruby 0.2.0 → 0.3.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.
- data/History.txt +32 -24
- data/README.txt +66 -66
- data/Rakefile +26 -22
- data/bin/org-ruby +40 -40
- data/lib/org-ruby.rb +50 -48
- data/lib/org-ruby/headline.rb +75 -75
- data/lib/org-ruby/html_output_buffer.rb +81 -80
- data/lib/org-ruby/line.rb +173 -172
- data/lib/org-ruby/output_buffer.rb +154 -154
- data/lib/org-ruby/parser.rb +76 -72
- 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/block_code.html +30 -29
- 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 -0
- data/spec/html_examples/escape-pre.org +6 -0
- 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 -0
- data/spec/html_examples/only-list.org +3 -0
- data/spec/html_examples/only-table.html +6 -0
- data/spec/html_examples/only-table.org +5 -0
- 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 -0
- metadata +21 -5
- data/.bnsignore +0 -18
@@ -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.
|