cgi-spa 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/COPYING ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2009 Sam Ruby <rubys@intertwingly.net>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to
5
+ deal in the Software without restriction, including without limitation the
6
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
+ sell copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README CHANGED
@@ -1,23 +1,55 @@
1
- Provides the following globals:
2
- $cgi - Common Gateway Interface
3
- $params - Access to parameters
4
- $x - XmlBuilder instance
1
+ = cgi-spa: Common Gateway Interface for Single Page Applications
5
2
 
6
- $USER - user
7
- $HOME - user's home directory
8
- $HOST - server host
3
+ CGI-SPA provides a number of globals, helper methods, and monkey patches which
4
+ simplify the development of single page applications in the form of CGI
5
+ scripts.
9
6
 
10
- $HTTP_GET - request is an HTTP GET
11
- $HTTP_POST - request is an HTTP POST
12
- $XHR_JSON - request is XmlHttpRequest for JSON
7
+ == Globals provided
8
+ * $cgi - Common Gateway Interface
9
+ * $param - Access to parameters (read-only OpenStruct like interface)
10
+ * $x - XmlBuilder instance
11
+ * $USER - Host user id
12
+ * $HOME - Home directory
13
+ * $SERVER- Server name
14
+ * SELF - Request URI
15
+ * SELF? - Request URI with '?' appended (avoids spoiling the cache)
13
16
 
14
- Helper methods:
15
- submit: runs command (or block) as a deamon process
17
+ * $USER - user
18
+ * $HOME - user's home directory
19
+ * $HOST - server host
16
20
 
17
- MonkeyPatches to Builder:
18
- indented_text: matches text indentation to markup
19
- indented_data: useful for script and styles in HTML syntax
20
- traceback! : formats an exception traceback
21
+ * $HTTP_GET - request is an HTTP GET
22
+ * $HTTP_POST - request is an HTTP POST
23
+ * $XHR_JSON - request is XmlHttpRequest for JSON
24
+ * $XHTML - user agent accepts XHTML responses
21
25
 
22
- method_missing: patched to ensure open tags are closed
26
+ == HTML methods
27
+ * style! - argument is indented text/data
28
+ * script! - argument is indented text/data
23
29
 
30
+ == CGI methods
31
+ * json - produce JSON output using the block specified
32
+ * json! - produce JSON output using the block specified and exit
33
+ * html - produce HTML output using the block specified
34
+ * html! - produce HTML output using the block specified and exit
35
+ * post - execute block only if method is POST
36
+ * post! - if POST, produce HTML output using the block specified and exit
37
+
38
+ == Helper methods
39
+ * submit: runs command (or block) as a deamon process
40
+
41
+ == Builder extensions
42
+ * indented_text: matches text indentation to markup
43
+ * indented_data: useful for script and styles in HTML syntax
44
+ * traceback!: formats an exception traceback
45
+ * method_missing: patched to ensure open tags are closed
46
+
47
+ == Command line options
48
+ When run from the command line, CGI name=value pairs can be specified.
49
+ Additionally, the following options are supported:
50
+ * --html: HTML (HTTP GET) output is expected
51
+ * --post: HTML (HTTP POST) output is expected
52
+ * --json: JSON (XML HTTP Request) output is expected
53
+ * --xhtml: XHTML output is expected
54
+ * --prompt: prompt for key/value pairs using stdin
55
+ * --install=path: produce an suexec-callable wrapper script
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require 'rubygems'
2
2
  require 'rake'
3
3
  require 'echoe'
4
4
 
5
- require File.expand_path(File.dirname(__FILE__) + "/lib/version")
5
+ require File.expand_path(File.dirname(__FILE__) + "/lib/cgi-spa/version")
6
6
 
7
7
  Echoe.new('cgi-spa', CgiSpa::VERSION::STRING) do |p|
8
8
  p.summary = "CGI Single Page Applications"
data/cgi-spa.gemspec CHANGED
@@ -2,18 +2,18 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{cgi-spa}
5
- s.version = "0.2.1"
5
+ s.version = "0.3.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Sam Ruby"]
9
- s.date = %q{2009-12-18}
9
+ s.date = %q{2009-12-19}
10
10
  s.description = %q{ Provides a number of globals, helper methods, and monkey patches which
11
11
  simplify the development of single page applications in the form of
12
12
  CGI scripts.
13
13
  }
14
14
  s.email = %q{rubys@intertwingly.net}
15
- s.extra_rdoc_files = ["README", "lib/cgi-spa.rb", "lib/version.rb"]
16
- s.files = ["Manifest", "README", "Rakefile", "cgi-spa.gemspec", "lib/cgi-spa.rb", "lib/version.rb"]
15
+ s.extra_rdoc_files = ["COPYING", "README", "lib/cgi-spa.rb", "lib/cgi-spa/builder.rb", "lib/cgi-spa/cgi-methods.rb", "lib/cgi-spa/environment.rb", "lib/cgi-spa/html-methods.rb", "lib/cgi-spa/installation.rb", "lib/cgi-spa/job-control.rb", "lib/cgi-spa/version.rb"]
16
+ s.files = ["COPYING", "Manifest", "README", "Rakefile", "cgi-spa.gemspec", "lib/cgi-spa.rb", "lib/cgi-spa/builder.rb", "lib/cgi-spa/cgi-methods.rb", "lib/cgi-spa/environment.rb", "lib/cgi-spa/html-methods.rb", "lib/cgi-spa/installation.rb", "lib/cgi-spa/job-control.rb", "lib/cgi-spa/version.rb"]
17
17
  s.homepage = %q{http://github.com/rubys/cgi-spa}
18
18
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Cgi-spa", "--main", "README"]
19
19
  s.require_paths = ["lib"]
@@ -0,0 +1,102 @@
1
+ # add indented_text!, indented_data! and traceback! methods to builder
2
+ module Builder
3
+ class XmlMarkup
4
+ unless method_defined? :indented_text!
5
+ def indented_text!(text)
6
+ indented_data!(text) {|data| text! data}
7
+ end
8
+ end
9
+
10
+ unless method_defined? :indented_data!
11
+ def indented_data!(data)
12
+ return if data.strip.length == 0
13
+ lines = data.gsub(/\n\s*\n/,"\n")
14
+ unindent = lines.scan(/^ */).map {|str| str.length}.min
15
+
16
+ before = Regexp.new('^'.ljust(unindent+1))
17
+ after = " " * (@level * @indent)
18
+ data = data.gsub(before, after)
19
+
20
+ if block_given?
21
+ yield data
22
+ else
23
+ self << data
24
+ end
25
+
26
+ _newline unless data =~ /\s$/
27
+ end
28
+ end
29
+
30
+ unless method_defined? :traceback!
31
+ def traceback!(exception=$!, klass='traceback')
32
+ pre :class=>klass do
33
+ text! exception.inspect
34
+ _newline
35
+ exception.backtrace.each {|frame| text!((' '*@indent)+frame + "\n")}
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ # monkey patch to ensure that tags are closed
43
+ test =
44
+ Builder::XmlMarkup.new.html do |x|
45
+ x.body do
46
+ begin
47
+ x.p do
48
+ raise Exception.new('boom')
49
+ end
50
+ rescue Exception => e
51
+ x.pre e
52
+ end
53
+ end
54
+ end
55
+
56
+ if test.index('<p>') and !test.index('</p>')
57
+ module Builder
58
+ class XmlMarkup
59
+ def method_missing(sym, *args, &block)
60
+ text = nil
61
+ attrs = nil
62
+ sym = "#{sym}:#{args.shift}" if args.first.kind_of?(Symbol)
63
+ args.each do |arg|
64
+ case arg
65
+ when Hash
66
+ attrs ||= {}
67
+ attrs.merge!(arg)
68
+ else
69
+ text ||= ''
70
+ text << arg.to_s
71
+ end
72
+ end
73
+ if block
74
+ unless text.nil?
75
+ raise ArgumentError, "XmlMarkup cannot mix a text argument with a block"
76
+ end
77
+ _indent
78
+ _start_tag(sym, attrs)
79
+ _newline
80
+ begin ### Added
81
+ _nested_structures(block)
82
+ ensure ### Added
83
+ _indent
84
+ _end_tag(sym)
85
+ _newline
86
+ end ### Added
87
+ elsif text.nil?
88
+ _indent
89
+ _start_tag(sym, attrs, true)
90
+ _newline
91
+ else
92
+ _indent
93
+ _start_tag(sym, attrs)
94
+ text! text
95
+ _end_tag(sym)
96
+ _newline
97
+ end
98
+ @target
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,51 @@
1
+ # produce json
2
+ def $cgi.json
3
+ return unless $XHR_JSON
4
+ $cgi.out 'type' => 'application/json', 'Cache-Control' => 'no-cache' do
5
+ JSON.pretty_generate(yield)+ "\n"
6
+ end
7
+ end
8
+
9
+ # produce json and quit
10
+ def $cgi.json! &block
11
+ return unless $XHR_JSON
12
+ json(&block)
13
+ Process.exit
14
+ end
15
+
16
+ # produce html/xhtml
17
+ def $cgi.html
18
+ return if $XHR_JSON
19
+ if $XHTML
20
+ $cgi.out 'type' => 'application/xhtml+xml', 'charset' => 'UTF-8' do
21
+ $x.declare! :DOCTYPE, :html
22
+ $x.html :xmlns => 'http://www.w3.org/1999/xhtml' do
23
+ yield $x
24
+ end
25
+ end
26
+ else
27
+ $cgi.out 'type' => 'text/html', 'charset' => 'UTF-8' do
28
+ $x.declare! :DOCTYPE, :html
29
+ $x.html do
30
+ yield $x
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ # produce html and quit
37
+ def $cgi.html! &block
38
+ return if $XHR_JSON
39
+ html(&block)
40
+ Process.exit
41
+ end
42
+
43
+ # post specific logic (doesn't produce output)
44
+ def $cgi.post
45
+ yield unless $HTML_POST
46
+ end
47
+
48
+ # post specific content (produces output)
49
+ def $cgi.post! &block
50
+ html!(&block) unless $HTML_POST
51
+ end
@@ -0,0 +1,45 @@
1
+ # explicit request types
2
+ $HTTP_GET = ARGV.delete('--html')
3
+ $HTTP_POST = ARGV.delete('--post')
4
+ $XHR_JSON = ARGV.delete('--json')
5
+ $XHTML = ARGV.delete('--xhtml')
6
+
7
+ # Only prompt if explicitly asked for
8
+ ARGV.push '' if ARGV.empty?
9
+ ARGV.delete('--prompt') or ARGV.delete('--offline')
10
+
11
+ # standard objects
12
+ $cgi = CGI.new
13
+ $param = $cgi.params
14
+ $x = Builder::XmlMarkup.new :indent => 2
15
+
16
+ # implied request types
17
+ $HTTP_GET ||= ($cgi.request_method == 'GET')
18
+ $HTTP_POST ||= ($cgi.request_method == 'POST')
19
+ $XHR_JSON ||= ($cgi.accept.to_s =~ /json/)
20
+ $XHTML ||= ($cgi.accept.to_s =~ /xhtml/)
21
+
22
+ # get arguments if CGI couldn't find any...
23
+ $param.merge!(CGI.parse(ARGV.join('&'))) if $param.empty?
24
+
25
+ # fast path for accessing CGI parameters
26
+ def $param.method_missing(name)
27
+ self[name.to_s].join if has_key? name.to_s
28
+ end
29
+
30
+ # quick access to request_uri
31
+ SELF = ENV['REQUEST_URI'].to_s
32
+ def SELF?
33
+ SELF + "?" # avoids spoiling the cache
34
+ end
35
+
36
+ # environment objects
37
+ $USER = ENV['USER'] ||
38
+ if RUBY_PLATFORM =~ /darwin/
39
+ `dscl . -search /Users UniqueID #{Process.uid}`.split.first
40
+ else
41
+ `getent passwd #{Process.uid}`.split(':').first
42
+ end
43
+
44
+ $HOME = ENV['HOME'] || File.expand_path('~' + $USER)
45
+ $SERVER = ENV['HTTP_HOST'] || `hostname`.chomp
@@ -0,0 +1,25 @@
1
+ # smart style, knows that the content is indented text/data
2
+ def $x.style!(text)
3
+ text.slice! /^\n/
4
+ text.slice! /[ ]+\z/
5
+ $x.style :type => "text/css" do
6
+ if $XHTML
7
+ indented_text! text
8
+ else
9
+ indented_data! text
10
+ end
11
+ end
12
+ end
13
+
14
+ # smart script, knows that the content is indented text/data
15
+ def $x.script!(text)
16
+ text.slice! /^\n/
17
+ text.slice! /[ ]+\z/
18
+ $x.script :lang => "text/javascript" do
19
+ if $XHTML
20
+ indented_text! text
21
+ else
22
+ indented_data! text
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,54 @@
1
+ # option to create an suexec callable wrapper
2
+ install = ARGV.find {|arg| arg =~ /--install=(.*)/}
3
+ if install and ARGV.delete(install)
4
+
5
+ # scope out the situation
6
+ dest = File.expand_path($1)
7
+ main = File.expand_path(caller.last[/^(.*):\d+(:|$)/,1])
8
+
9
+ # if destination is a directory, determine an appropriate file name
10
+ if File.directory?(dest)
11
+ if dest =~ /\/cgi-bin\/?$/
12
+ dest = File.join(dest, File.basename(main))
13
+ else
14
+ dest = File.join(dest, File.basename(main).sub(/\.rb$/,'.cgi'))
15
+ end
16
+ end
17
+
18
+ # prevent accidental overwrite
19
+ if File.exist?(dest) and not ARGV.delete('-f')
20
+ STDERR.puts "File #{dest} already exists. (Specify -f to overwrite)"
21
+ Process.exit
22
+ end
23
+
24
+ # ensure destination directory exists
25
+ destdir = File.dirname(dest)
26
+ if not File.exist?(destdir) or not File.directory?(destdir)
27
+ STDERR.puts "Directory #{destdir} does not exist."
28
+ Process.exit
29
+ end
30
+
31
+ # output wrapper
32
+ open(dest,'w') do |file|
33
+ # she-bang
34
+ file.puts "#!" + File.join(
35
+ RbConfig::CONFIG["bindir"],
36
+ RbConfig::CONFIG["ruby_install_name"] + RbConfig::CONFIG["EXEEXT"]
37
+ )
38
+
39
+ # Change directory
40
+ file.puts "Dir.chdir #{File.dirname(main).inspect}"
41
+
42
+ # Optional data from the script (after __END__)
43
+ file.puts DATA.read if Object.const_defined? :DATA
44
+
45
+ # Load script
46
+ file.puts "require #{File.basename(main).sub(/\.rb$/,'').inspect}"
47
+ end
48
+
49
+ # Mark wrapper as executable
50
+ File.chmod(0755, dest)
51
+
52
+ # Don't execute the script itself at this time
53
+ Process.exit
54
+ end
@@ -0,0 +1,25 @@
1
+ # run command/block as a background daemon
2
+ def submit(cmd=nil)
3
+ fork do
4
+ # detach from tty
5
+ Process.setsid
6
+ fork and exit
7
+
8
+ # clear working directory and mask
9
+ Dir.chdir '/'
10
+ File.umask 0000
11
+
12
+ # close open files
13
+ STDIN.reopen '/dev/null'
14
+ STDOUT.reopen '/dev/null', 'a'
15
+ STDERR.reopen STDOUT
16
+
17
+ # setup environment
18
+ ENV['USER'] ||= $USER
19
+ ENV['HOME'] ||= $HOME
20
+
21
+ # run cmd and/or block
22
+ system cmd if cmd
23
+ yield if block_given?
24
+ end
25
+ end
@@ -1,8 +1,8 @@
1
1
  module CgiSpa
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
- MINOR = 2
5
- TINY = 1
4
+ MINOR = 3
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
data/lib/cgi-spa.rb CHANGED
@@ -1,169 +1,11 @@
1
- #!/usr/bin/ruby
2
1
  require 'cgi'
3
- require 'rubygems'
4
2
  require 'builder'
5
3
  require 'json'
6
4
 
7
- # standard objects
8
- $cgi = CGI.new
9
- $param = $cgi.params
10
- $x = Builder::XmlMarkup.new :indent => 2
5
+ require 'cgi-spa/environment'
6
+ require 'cgi-spa/cgi-methods'
7
+ require 'cgi-spa/html-methods'
8
+ require 'cgi-spa/job-control'
9
+ require 'cgi-spa/installation'
10
+ require 'cgi-spa/builder'
11
11
 
12
- # get arguments if CGI couldn't find any...
13
- $param.merge!(CGI.parse(ARGV.join('&'))) if $param.empty?
14
-
15
- # fast path for accessing CGI parameters
16
- def $param.method_missing(name)
17
- self[name.to_s].join if has_key? name.to_s
18
- end
19
-
20
- # quick access to request_uri
21
- SELF = ENV['REQUEST_URI'].to_s
22
- def SELF?
23
- SELF + "?" # avoids spoiling the cache
24
- end
25
-
26
- # environment objects
27
- $USER = ENV['USER'] ||
28
- if RUBY_PLATFORM =~ /darwin/
29
- `dscl . -search /Users UniqueID #{Process.uid}`.split.first
30
- else
31
- `getent passwd #{Process.uid}`.split(':').first
32
- end
33
-
34
- $HOME = ENV['HOME'] || File.expand_path('~' + $USER)
35
- $SERVER = ENV['HTTP_HOST'] || `hostname`.chomp
36
-
37
- # request types
38
- $HTTP_GET = ($cgi.request_method == 'GET')
39
- $HTTP_POST = ($cgi.request_method == 'POST')
40
- $XHR_JSON = (ENV['HTTP_ACCEPT'] =~ /json/)
41
-
42
- # run command/block as a background daemon
43
- def submit(cmd=nil)
44
- fork do
45
- # detach from tty
46
- Process.setsid
47
- fork and exit
48
-
49
- # clear working directory and mask
50
- Dir.chdir '/'
51
- File.umask 0000
52
-
53
- # close open files
54
- STDIN.reopen '/dev/null'
55
- STDOUT.reopen '/dev/null', 'a'
56
- STDERR.reopen STDOUT
57
-
58
- # setup environment
59
- ENV['USER'] ||= $USER
60
- ENV['HOME'] ||= $HOME
61
-
62
- # run cmd and/or block
63
- system cmd if cmd
64
- yield if block_given?
65
- end
66
- end
67
-
68
- # add indented_text!, indented_data! and traceback! methods to builder
69
- module Builder
70
- class XmlMarkup
71
- unless method_defined? :indented_text!
72
- def indented_text!(text)
73
- indented_data!(text) {|data| text! data}
74
- end
75
- end
76
-
77
- unless method_defined? :indented_data!
78
- def indented_data!(data)
79
- return if data.strip.length == 0
80
- lines = data.gsub(/\n\s*\n/,"\n")
81
- unindent = lines.scan(/^ */).map {|str| str.length}.min
82
-
83
- before = Regexp.new('^'.ljust(unindent+1))
84
- after = " " * (@level * @indent)
85
- data = data.gsub(before, after)
86
-
87
- if block_given?
88
- yield data
89
- else
90
- self << data
91
- end
92
-
93
- _newline unless data =~ /\s$/
94
- end
95
- end
96
-
97
- unless method_defined? :traceback!
98
- def traceback!(exception=$!, klass='traceback')
99
- pre :class=>klass do
100
- text! exception.inspect
101
- _newline
102
- exception.backtrace.each {|frame| text!((' '*@indent)+frame + "\n")}
103
- end
104
- end
105
- end
106
- end
107
- end
108
-
109
- # monkey patch to ensure that tags are closed
110
- test =
111
- Builder::XmlMarkup.new.html do |x|
112
- x.body do
113
- begin
114
- x.p do
115
- raise Exception.new('boom')
116
- end
117
- rescue Exception => e
118
- x.pre e
119
- end
120
- end
121
- end
122
-
123
- if test.index('<p>') and !test.index('</p>')
124
- module Builder
125
- class XmlMarkup
126
- def method_missing(sym, *args, &block)
127
- text = nil
128
- attrs = nil
129
- sym = "#{sym}:#{args.shift}" if args.first.kind_of?(Symbol)
130
- args.each do |arg|
131
- case arg
132
- when Hash
133
- attrs ||= {}
134
- attrs.merge!(arg)
135
- else
136
- text ||= ''
137
- text << arg.to_s
138
- end
139
- end
140
- if block
141
- unless text.nil?
142
- raise ArgumentError, "XmlMarkup cannot mix a text argument with a block"
143
- end
144
- _indent
145
- _start_tag(sym, attrs)
146
- _newline
147
- begin ### Added
148
- _nested_structures(block)
149
- ensure ### Added
150
- _indent
151
- _end_tag(sym)
152
- _newline
153
- end ### Added
154
- elsif text.nil?
155
- _indent
156
- _start_tag(sym, attrs, true)
157
- _newline
158
- else
159
- _indent
160
- _start_tag(sym, attrs)
161
- text! text
162
- _end_tag(sym)
163
- _newline
164
- end
165
- @target
166
- end
167
- end
168
- end
169
- end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cgi-spa
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Ruby
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-12-18 00:00:00 -05:00
12
+ date: 2009-12-19 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -39,16 +39,30 @@ executables: []
39
39
  extensions: []
40
40
 
41
41
  extra_rdoc_files:
42
+ - COPYING
42
43
  - README
43
44
  - lib/cgi-spa.rb
44
- - lib/version.rb
45
+ - lib/cgi-spa/builder.rb
46
+ - lib/cgi-spa/cgi-methods.rb
47
+ - lib/cgi-spa/environment.rb
48
+ - lib/cgi-spa/html-methods.rb
49
+ - lib/cgi-spa/installation.rb
50
+ - lib/cgi-spa/job-control.rb
51
+ - lib/cgi-spa/version.rb
45
52
  files:
53
+ - COPYING
46
54
  - Manifest
47
55
  - README
48
56
  - Rakefile
49
57
  - cgi-spa.gemspec
50
58
  - lib/cgi-spa.rb
51
- - lib/version.rb
59
+ - lib/cgi-spa/builder.rb
60
+ - lib/cgi-spa/cgi-methods.rb
61
+ - lib/cgi-spa/environment.rb
62
+ - lib/cgi-spa/html-methods.rb
63
+ - lib/cgi-spa/installation.rb
64
+ - lib/cgi-spa/job-control.rb
65
+ - lib/cgi-spa/version.rb
52
66
  has_rdoc: true
53
67
  homepage: http://github.com/rubys/cgi-spa
54
68
  licenses: []