vanilla 1.0.2 → 1.2
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/Rakefile +112 -109
- data/bin/vanilla +35 -6
- data/lib/vanilla.rb +10 -14
- data/lib/vanilla/app.rb +109 -41
- data/lib/vanilla/console.rb +22 -2
- data/lib/vanilla/dynasnip.rb +4 -36
- data/lib/vanilla/renderers.rb +12 -0
- data/lib/vanilla/renderers/base.rb +58 -34
- data/lib/vanilla/renderers/bold.rb +0 -2
- data/lib/vanilla/renderers/erb.rb +1 -3
- data/lib/vanilla/renderers/haml.rb +13 -0
- data/lib/vanilla/renderers/markdown.rb +0 -2
- data/lib/vanilla/renderers/raw.rb +0 -2
- data/lib/vanilla/renderers/ruby.rb +12 -6
- data/lib/vanilla/renderers/textile.rb +0 -2
- data/lib/vanilla/request.rb +19 -17
- data/lib/vanilla/routes.rb +9 -20
- data/lib/vanilla/snip_reference_parser.rb +94 -0
- data/lib/vanilla/static.rb +28 -0
- data/pristine_app/Gemfile +3 -0
- data/pristine_app/Gemfile.lock +32 -0
- data/pristine_app/README +47 -0
- data/pristine_app/config.ru +26 -0
- data/pristine_app/public/vanilla.css +15 -0
- data/pristine_app/soups/base/layout.snip +18 -0
- data/pristine_app/soups/base/start.snip +19 -0
- data/pristine_app/soups/dynasnips/current_snip.rb +29 -0
- data/{lib/vanilla → pristine_app/soups}/dynasnips/debug.rb +5 -3
- data/pristine_app/soups/dynasnips/index.rb +12 -0
- data/{lib/vanilla → pristine_app/soups}/dynasnips/link_to.rb +4 -2
- data/pristine_app/soups/dynasnips/link_to_current_snip.rb +14 -0
- data/pristine_app/soups/dynasnips/page_title.rb +9 -0
- data/{lib/vanilla → pristine_app/soups}/dynasnips/pre.rb +7 -5
- data/{lib/vanilla → pristine_app/soups}/dynasnips/raw.rb +8 -5
- data/pristine_app/soups/extras/comments.rb +78 -0
- data/{lib/vanilla/dynasnips → pristine_app/soups/extras}/kind.rb +19 -17
- data/{lib/vanilla/dynasnips → pristine_app/soups/extras}/rand.rb +2 -0
- data/pristine_app/soups/extras/url_to.rb +7 -0
- data/pristine_app/soups/tutorial/bad_dynasnip.snip +8 -0
- data/pristine_app/soups/tutorial/hello_world.snip +20 -0
- data/pristine_app/soups/tutorial/markdown_example.snip +13 -0
- data/pristine_app/soups/tutorial/snip.snip +9 -0
- data/pristine_app/soups/tutorial/soup.snip +3 -0
- data/pristine_app/soups/tutorial/test.snip +30 -0
- data/pristine_app/soups/tutorial/textile_example.snip +11 -0
- data/pristine_app/soups/tutorial/tutorial-another-snip.snip +1 -0
- data/pristine_app/soups/tutorial/tutorial-basic-snip-inclusion.snip +1 -0
- data/pristine_app/soups/tutorial/tutorial-dynasnips.snip.markdown +56 -0
- data/pristine_app/soups/tutorial/tutorial-layout.snip +56 -0
- data/pristine_app/soups/tutorial/tutorial-links.snip +4 -0
- data/pristine_app/soups/tutorial/tutorial-renderers.snip.markdown +77 -0
- data/pristine_app/soups/tutorial/tutorial.snip.markdown +69 -0
- data/pristine_app/soups/tutorial/vanilla-rb.snip +16 -0
- data/pristine_app/soups/tutorial/vanilla.snip +8 -0
- data/test/dynasnip_test.rb +42 -0
- data/test/dynasnips/link_to_current_snip_test.rb +19 -0
- data/test/dynasnips/link_to_test.rb +27 -0
- data/test/dynasnips/page_title_test.rb +19 -0
- data/test/renderers/base_renderer_test.rb +43 -0
- data/test/renderers/erb_renderer_test.rb +29 -0
- data/test/renderers/haml_renderer_test.rb +35 -0
- data/test/renderers/markdown_renderer_test.rb +31 -0
- data/test/renderers/raw_renderer_test.rb +23 -0
- data/test/renderers/ruby_renderer_test.rb +59 -0
- data/test/snip_inclusion_test.rb +56 -0
- data/test/snip_reference_parser_test.rb +123 -0
- data/test/test_helper.rb +75 -0
- data/test/vanilla_app_test.rb +83 -0
- data/test/vanilla_presenting_test.rb +125 -0
- data/test/vanilla_request_test.rb +87 -0
- metadata +179 -78
- data/config.example.yml +0 -5
- data/config.ru +0 -9
- data/lib/defensio.rb +0 -59
- data/lib/tasks/vanilla.rake +0 -177
- data/lib/vanilla/dynasnips/comments.rb +0 -108
- data/lib/vanilla/dynasnips/current_snip.rb +0 -32
- data/lib/vanilla/dynasnips/edit.rb +0 -63
- data/lib/vanilla/dynasnips/edit_link.rb +0 -24
- data/lib/vanilla/dynasnips/index.rb +0 -11
- data/lib/vanilla/dynasnips/link_to_current_snip.rb +0 -16
- data/lib/vanilla/dynasnips/login.rb +0 -56
- data/lib/vanilla/dynasnips/new.rb +0 -14
- data/lib/vanilla/dynasnips/notes.rb +0 -42
- data/lib/vanilla/dynasnips/url_to.rb +0 -7
- data/lib/vanilla/snip_handling.rb +0 -33
- data/lib/vanilla/snips/start.rb +0 -27
- data/lib/vanilla/snips/system.rb +0 -76
- data/lib/vanilla/snips/tutorial.rb +0 -157
- data/lib/vanilla/test_snips.rb +0 -85
- data/public/hatch.png +0 -0
- data/public/javascripts/jquery.js +0 -3549
- data/public/javascripts/vanilla.js +0 -21
- data/spec/dynasnip_spec.rb +0 -31
- data/spec/renderers/base_renderer_spec.rb +0 -40
- data/spec/renderers/erb_renderer_spec.rb +0 -27
- data/spec/renderers/markdown_renderer_spec.rb +0 -29
- data/spec/renderers/raw_renderer_spec.rb +0 -21
- data/spec/renderers/ruby_renderer_spec.rb +0 -42
- data/spec/renderers/vanilla_app_detecting_renderer_spec.rb +0 -35
- data/spec/spec_helper.rb +0 -64
- data/spec/vanilla_app_spec.rb +0 -38
- data/spec/vanilla_presenting_spec.rb +0 -84
- data/spec/vanilla_request_spec.rb +0 -73
- data/spec/vanilla_snip_finding_spec.rb +0 -28
data/lib/vanilla/console.rb
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
1
|
require 'vanilla'
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
|
|
3
|
+
module Vanilla
|
|
4
|
+
class RackShim
|
|
5
|
+
def run(app)
|
|
6
|
+
app # return it
|
|
7
|
+
end
|
|
8
|
+
def use(*args)
|
|
9
|
+
# ignore
|
|
10
|
+
end
|
|
11
|
+
def get_binding
|
|
12
|
+
binding
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def app(reload=false)
|
|
18
|
+
if !@__vanilla_console_app || reload
|
|
19
|
+
shim_binding = Vanilla::RackShim.new.get_binding
|
|
20
|
+
@__vanilla_console_app = eval File.read("config.ru"), shim_binding
|
|
21
|
+
end
|
|
22
|
+
@__vanilla_console_app
|
|
23
|
+
end
|
data/lib/vanilla/dynasnip.rb
CHANGED
|
@@ -29,48 +29,16 @@ class Dynasnip < Vanilla::Renderers::Base
|
|
|
29
29
|
attribute :usage, escape_curly_braces(str).strip
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
def self.persist_all!(overwrite=false)
|
|
33
|
-
all.each do |dynasnip|
|
|
34
|
-
dynasnip.persist!(overwrite)
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def self.build_snip
|
|
39
|
-
Snip.new(snip_attributes)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
32
|
def self.snip_attributes
|
|
43
33
|
full_snip_attributes = {:name => snip_name, :content => self.name, :render_as => "Ruby"}
|
|
44
34
|
@attributes ? full_snip_attributes.merge!(@attributes) : full_snip_attributes
|
|
45
35
|
end
|
|
46
36
|
|
|
47
|
-
|
|
48
|
-
if overwrite
|
|
49
|
-
snip = Soup[snip_name]
|
|
50
|
-
if snip
|
|
51
|
-
if snip.is_a?(Array)
|
|
52
|
-
snip.each { |s| s.destroy }
|
|
53
|
-
else
|
|
54
|
-
snip.destroy
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
snip = Soup[snip_name]
|
|
59
|
-
snip = snip[0] if snip.is_a?(Array)
|
|
60
|
-
if snip
|
|
61
|
-
snip_attributes.each do |name, value|
|
|
62
|
-
snip.set_value(name, value)
|
|
63
|
-
end
|
|
64
|
-
else
|
|
65
|
-
snip = build_snip
|
|
66
|
-
end
|
|
67
|
-
snip.save
|
|
68
|
-
snip
|
|
69
|
-
end
|
|
37
|
+
attr_accessor :enclosing_snip
|
|
70
38
|
|
|
71
39
|
def method_missing(method, *args)
|
|
72
|
-
if snip
|
|
73
|
-
snip.
|
|
40
|
+
if snip
|
|
41
|
+
snip.__send__(method)
|
|
74
42
|
elsif part = self.class.attribute(method)
|
|
75
43
|
part
|
|
76
44
|
else
|
|
@@ -88,7 +56,7 @@ class Dynasnip < Vanilla::Renderers::Base
|
|
|
88
56
|
end
|
|
89
57
|
|
|
90
58
|
def snip
|
|
91
|
-
|
|
59
|
+
app.soup[snip_name]
|
|
92
60
|
end
|
|
93
61
|
|
|
94
62
|
def show_usage
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module Vanilla
|
|
2
|
+
module Renderers
|
|
3
|
+
autoload :Base, "vanilla/renderers/base"
|
|
4
|
+
autoload :Bold, "vanilla/renderers/bold"
|
|
5
|
+
autoload :Erb, "vanilla/renderers/erb"
|
|
6
|
+
autoload :Haml, "vanilla/renderers/haml"
|
|
7
|
+
autoload :Markdown, "vanilla/renderers/markdown"
|
|
8
|
+
autoload :Raw, "vanilla/renderers/raw"
|
|
9
|
+
autoload :Ruby, "vanilla/renderers/ruby"
|
|
10
|
+
autoload :Textile, "vanilla/renderers/textile"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -1,74 +1,98 @@
|
|
|
1
|
-
require 'vanilla/
|
|
1
|
+
require 'vanilla/snip_reference_parser'
|
|
2
2
|
|
|
3
3
|
module Vanilla
|
|
4
4
|
module Renderers
|
|
5
5
|
class Base
|
|
6
|
-
|
|
6
|
+
include Routes
|
|
7
|
+
|
|
7
8
|
# Render a snip.
|
|
8
9
|
def self.render(snip, part=:content)
|
|
9
10
|
new(app).render(snip, part)
|
|
10
11
|
end
|
|
11
|
-
|
|
12
|
+
|
|
12
13
|
def self.escape_curly_braces(str)
|
|
13
14
|
str.gsub("{", "{").gsub("}", "}")
|
|
14
15
|
end
|
|
15
|
-
|
|
16
|
+
|
|
16
17
|
attr_reader :app
|
|
17
|
-
|
|
18
|
+
|
|
18
19
|
def initialize(app)
|
|
19
20
|
@app = app
|
|
20
21
|
end
|
|
21
|
-
|
|
22
|
+
|
|
23
|
+
# defined for the routes
|
|
24
|
+
def soup
|
|
25
|
+
@app.soup
|
|
26
|
+
end
|
|
27
|
+
|
|
22
28
|
def self.snip_regexp
|
|
23
|
-
%r{
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
%r{(\{[\w\-_\d\.\"\'\s]+(\s+[^\}.]+)?\})}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def default_layout_snip
|
|
33
|
+
app.default_layout_snip
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def layout_for(snip)
|
|
37
|
+
layout_snip = (snip && snip.layout) ? soup[snip.layout] : default_layout_snip
|
|
27
38
|
end
|
|
28
|
-
|
|
39
|
+
|
|
29
40
|
# Default behaviour to include a snip's content
|
|
30
|
-
def include_snips(content)
|
|
41
|
+
def include_snips(content, enclosing_snip)
|
|
31
42
|
content.gsub(Vanilla::Renderers::Base.snip_regexp) do
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
snip_tree = parse_snip_reference($1)
|
|
44
|
+
if snip_tree
|
|
45
|
+
snip_name = snip_tree.snip
|
|
46
|
+
snip_attribute = snip_tree.attribute
|
|
47
|
+
snip_args = snip_tree.arguments
|
|
48
|
+
|
|
49
|
+
# Render the snip or snip part with the given args, and the current
|
|
50
|
+
# context, but with the default renderer for that snip. We dispatch
|
|
51
|
+
# *back* out to the root Vanilla.render method to do this.
|
|
52
|
+
if snip = soup[snip_name]
|
|
53
|
+
app.render(snip, snip_attribute, snip_args, enclosing_snip)
|
|
54
|
+
else
|
|
55
|
+
render_missing_snip(snip_name)
|
|
56
|
+
end
|
|
42
57
|
else
|
|
43
|
-
|
|
58
|
+
"malformed snip reference: #{$1.inspect}"
|
|
44
59
|
end
|
|
45
60
|
end
|
|
46
61
|
end
|
|
47
|
-
|
|
62
|
+
|
|
63
|
+
def parse_snip_reference(string)
|
|
64
|
+
@parser ||= Vanilla::SnipReferenceParser.new
|
|
65
|
+
@parser.parse(string)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def render_missing_snip(snip_name)
|
|
69
|
+
"[snip '#{snip_name}' cannot be found]"
|
|
70
|
+
end
|
|
71
|
+
|
|
48
72
|
# Default rendering behaviour. Subclasses shouldn't really need to touch this.
|
|
49
|
-
def render(snip, part=:content, args=[])
|
|
50
|
-
prepare(snip, part, args)
|
|
73
|
+
def render(snip, part=:content, args=[], enclosing_snip=snip)
|
|
74
|
+
prepare(snip, part, args, enclosing_snip)
|
|
51
75
|
processed_text = render_without_including_snips(snip, part)
|
|
52
|
-
include_snips(processed_text)
|
|
76
|
+
include_snips(processed_text, snip)
|
|
53
77
|
end
|
|
54
|
-
|
|
78
|
+
|
|
55
79
|
# Subclasses should override this to perform any actions required before
|
|
56
80
|
# rendering
|
|
57
|
-
def prepare(snip, part, args)
|
|
81
|
+
def prepare(snip, part, args, enclosing_snip)
|
|
58
82
|
# do nothing, by default
|
|
59
83
|
end
|
|
60
|
-
|
|
84
|
+
|
|
61
85
|
def render_without_including_snips(snip, part=:content)
|
|
62
86
|
process_text(raw_content(snip, part))
|
|
63
87
|
end
|
|
64
|
-
|
|
65
|
-
# Handles processing the text of the content.
|
|
66
|
-
# Subclasses should override this method to do fancy text processing
|
|
88
|
+
|
|
89
|
+
# Handles processing the text of the content.
|
|
90
|
+
# Subclasses should override this method to do fancy text processing
|
|
67
91
|
# like markdown, or loading the content as Ruby code.
|
|
68
92
|
def process_text(content)
|
|
69
93
|
content
|
|
70
94
|
end
|
|
71
|
-
|
|
95
|
+
|
|
72
96
|
# Returns the raw content for the selected part of the selected snip
|
|
73
97
|
def raw_content(snip, part)
|
|
74
98
|
snip.__send__((part || :content).to_sym)
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require 'vanilla/renderers/base'
|
|
2
|
-
|
|
3
1
|
module Vanilla::Renderers
|
|
4
2
|
# Snips that render_as "Ruby" should define a class.
|
|
5
3
|
# The class should have instance methods for any HTTP request methods that the dynasnip
|
|
@@ -13,9 +11,10 @@ module Vanilla::Renderers
|
|
|
13
11
|
# itself), it should be a subclass of Dynasnip (or define an initializer
|
|
14
12
|
# that accepts the context as its first argument).
|
|
15
13
|
class Ruby < Base
|
|
16
|
-
def prepare(snip, part=:content, args=[])
|
|
14
|
+
def prepare(snip, part=:content, args=[], enclosing_snip=snip)
|
|
17
15
|
@args = args
|
|
18
16
|
@snip = snip
|
|
17
|
+
@enclosing_snip = enclosing_snip
|
|
19
18
|
end
|
|
20
19
|
|
|
21
20
|
def process_text(content)
|
|
@@ -25,10 +24,17 @@ module Vanilla::Renderers
|
|
|
25
24
|
else
|
|
26
25
|
handler_klass.new
|
|
27
26
|
end
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
instance.enclosing_snip = @enclosing_snip if instance.respond_to?(:enclosing_snip)
|
|
28
|
+
|
|
29
|
+
if app.request && (method = app.request.method) && instance.respond_to?(method)
|
|
30
|
+
message = method
|
|
31
|
+
else
|
|
32
|
+
message = :handle
|
|
33
|
+
end
|
|
34
|
+
if @args.is_a?(Array)
|
|
35
|
+
instance.send(message, *@args).to_s
|
|
30
36
|
else
|
|
31
|
-
instance.
|
|
37
|
+
instance.send(message, @args).to_s
|
|
32
38
|
end
|
|
33
39
|
end
|
|
34
40
|
end
|
data/lib/vanilla/request.rb
CHANGED
|
@@ -4,10 +4,12 @@ module Vanilla
|
|
|
4
4
|
# Create a request with symbolised access to the params, and some special
|
|
5
5
|
# accessors to the snip, part and format based on our routing.
|
|
6
6
|
class Request
|
|
7
|
-
attr_reader :snip_name, :part, :format, :method
|
|
8
|
-
|
|
9
|
-
def initialize(env)
|
|
7
|
+
attr_reader :snip_name, :part, :format, :method, :env
|
|
8
|
+
|
|
9
|
+
def initialize(env, app)
|
|
10
|
+
@env = env
|
|
10
11
|
@rack_request = Rack::Request.new(env)
|
|
12
|
+
@app = app
|
|
11
13
|
determine_request_uri_parts
|
|
12
14
|
end
|
|
13
15
|
|
|
@@ -15,46 +17,46 @@ module Vanilla
|
|
|
15
17
|
# Don't you just love how terse functional programming tends to look like maths?
|
|
16
18
|
@symbolised_params ||= @rack_request.params.inject({}) { |p, (k,v)| p[k.to_sym] = v; p }
|
|
17
19
|
end
|
|
18
|
-
|
|
20
|
+
|
|
19
21
|
# Returns the snip referenced by the request's URL. Performs no exception
|
|
20
22
|
# handling, so if the snip does not exist, an exception will be thrown.
|
|
21
23
|
def snip
|
|
22
|
-
|
|
24
|
+
@app.soup[snip_name]
|
|
23
25
|
end
|
|
24
|
-
|
|
26
|
+
|
|
25
27
|
def cookies
|
|
26
28
|
@rack_request.cookies
|
|
27
29
|
end
|
|
28
|
-
|
|
30
|
+
|
|
29
31
|
def ip
|
|
30
32
|
@rack_request.env["REMOTE_ADDR"]
|
|
31
33
|
end
|
|
32
|
-
|
|
34
|
+
|
|
33
35
|
def session
|
|
34
36
|
@rack_request.env["rack.session"]
|
|
35
37
|
end
|
|
36
|
-
|
|
38
|
+
|
|
37
39
|
private
|
|
38
|
-
|
|
40
|
+
|
|
39
41
|
def determine_request_uri_parts
|
|
40
42
|
@snip_name, @part, @format = request_uri_parts(@rack_request)
|
|
41
43
|
@format ||= 'html'
|
|
42
44
|
@method = (params.delete(:_method) || @rack_request.request_method).downcase
|
|
43
45
|
end
|
|
44
|
-
|
|
46
|
+
|
|
45
47
|
def uri_path(request)
|
|
46
48
|
request.path_info
|
|
47
49
|
end
|
|
48
|
-
|
|
49
|
-
URL_ROOT = /\A
|
|
50
|
+
|
|
51
|
+
URL_ROOT = /\A\/?\Z/ # i.e. / or nothing
|
|
50
52
|
URL_SNIP = /\A\/([\w\-\s]+)(\/|\.(\w+))?\Z/ # i.e. /start, /start.html
|
|
51
53
|
URL_SNIP_AND_PART = /\A\/([\w\-\s]+)\/([\w\-\s]+)(\/|\.(\w+))?\Z/ # i.e. /blah/part, /blah/part.raw
|
|
52
|
-
|
|
54
|
+
|
|
53
55
|
# Returns an array of the requested snip, part and format
|
|
54
56
|
def request_uri_parts(request)
|
|
55
57
|
case CGI.unescape(uri_path(request))
|
|
56
58
|
when URL_ROOT
|
|
57
|
-
['start', nil, 'html']
|
|
59
|
+
[@app.config[:root_snip] || 'start', nil, 'html']
|
|
58
60
|
when URL_SNIP
|
|
59
61
|
[$1, nil, $3]
|
|
60
62
|
when URL_SNIP_AND_PART
|
|
@@ -63,6 +65,6 @@ module Vanilla
|
|
|
63
65
|
[]
|
|
64
66
|
end
|
|
65
67
|
end
|
|
66
|
-
|
|
68
|
+
|
|
67
69
|
end
|
|
68
|
-
end
|
|
70
|
+
end
|
data/lib/vanilla/routes.rb
CHANGED
|
@@ -1,29 +1,18 @@
|
|
|
1
1
|
module Vanilla
|
|
2
|
+
# Expects to be able to call 'soup' on whatever it is included into
|
|
2
3
|
module Routes
|
|
3
4
|
def link_to(link_text, snip_name=link_text, part=nil)
|
|
4
|
-
|
|
5
|
+
if soup[snip_name]
|
|
6
|
+
%{<a href="#{url_to(snip_name, part)}">#{link_text}</a>}
|
|
7
|
+
else
|
|
8
|
+
%{<a class="missing" href="#{url_to(snip_name, part)}">#{link_text}</a>}
|
|
9
|
+
end
|
|
5
10
|
end
|
|
6
|
-
|
|
11
|
+
|
|
7
12
|
def url_to(snip_name, part=nil)
|
|
8
|
-
url = "/#{snip_name}"
|
|
13
|
+
url = "/#{snip_name.gsub(" ", "+")}"
|
|
9
14
|
url += "/#{part}" if part
|
|
10
15
|
url
|
|
11
16
|
end
|
|
12
|
-
|
|
13
|
-
def url_to_raw(snip_name, part=nil)
|
|
14
|
-
url = "/#{snip_name}"
|
|
15
|
-
url += "/#{part}" if part
|
|
16
|
-
url += ".raw"
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def edit_link(snip_name, link_text)
|
|
20
|
-
%[<a href="/edit?name=#{snip_name}">#{link_text}</a>]
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def new_link(snip_name="New")
|
|
24
|
-
%[<a href="/new?name=#{snip_name}" class="new">#{snip_name}</a>]
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
extend self
|
|
28
17
|
end
|
|
29
|
-
end
|
|
18
|
+
end
|