rweb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,249 @@
1
+ # Rakefile
2
+ require "rake/testtask"
3
+ require "rake/clean"
4
+ require "rake/rdoctask"
5
+ require "rake/gempackagetask"
6
+ #---
7
+ # The name of your project
8
+ PROJECT = "RWEB"
9
+
10
+ # Your name, used in packaging.
11
+ MY_NAME = "Michael T. Richter"
12
+
13
+ # Your email address, used in packaging.
14
+ MY_EMAIL = "ttmrichter@gmail.com"
15
+
16
+ # Short summary of your project, used in packaging.
17
+ PROJECT_SUMMARY = "Self-executing WEB-like literate programming for Ruby."
18
+
19
+ # The project's package name (as opposed to its display name). Used for
20
+ # RubyForge connectivity and packaging.
21
+ UNIX_NAME = "rweb"
22
+
23
+ # Your RubyForge user name.
24
+ RUBYFORGE_USER = ENV["RUBYFORGE_USER"] || "mtr1966"
25
+
26
+ # Directory on RubyForge where your website's files should be uploaded.
27
+ WEBSITE_DIR = "rweb"
28
+
29
+ # Output directory for the rdoc html files.
30
+ # If you don't have a custom homepage, and want to use the RDoc
31
+ # index.html as homepage, just set it to WEBSITE_DIR.
32
+ RDOC_HTML_DIR = "#{WEBSITE_DIR}/rdoc"
33
+ #---
34
+ # Variable settings for extension support.
35
+ EXT_DIR = "ext"
36
+ HAVE_EXT = File.directory?(EXT_DIR)
37
+ EXTCONF_FILES = FileList["#{EXT_DIR}/**/extconf.rb"]
38
+ EXT_SOURCES = FileList["#{EXT_DIR}/**/*.{c,h}"]
39
+ # Eventually add other files from EXT_DIR, like "MANIFEST"
40
+ EXT_DIST_FILES = EXT_SOURCES + EXTCONF_FILES
41
+ #---
42
+ REQUIRE_PATHS = ["lib"]
43
+ REQUIRE_PATHS << EXT_DIR if HAVE_EXT
44
+ $LOAD_PATH.concat(REQUIRE_PATHS)
45
+ # This library file defines the MyProject::VERSION constant.
46
+ require "#{UNIX_NAME}"
47
+ PROJECT_VERSION = eval("#{PROJECT}::VERSION") # e.g. "1.0.2"
48
+ #---
49
+ # Clobber object files and Makefiles generated by extconf.rb.
50
+ CLOBBER.include("#{EXT_DIR}/**/*.{so,dll,o}", "#{EXT_DIR}/**/Makefile")
51
+ # Clobber .config generated by setup.rb.
52
+ CLOBBER.include(".config")
53
+ #---
54
+ # Options common to RDocTask AND Gem::Specification.
55
+ # The --main argument specifies which file appears on the index.html page
56
+ GENERAL_RDOC_OPTS = {
57
+ "--title" => "#{PROJECT} API documentation",
58
+ "--main" => "README.rdoc"
59
+ }
60
+
61
+ # Additional RDoc formatted files, besides the Ruby source files.
62
+ RDOC_FILES = FileList["README.rdoc", "Changes.rdoc", "TODO.rdoc"]
63
+ # Remove the following line if you don't want to extract RDoc from
64
+ # the extension C sources.
65
+ RDOC_FILES.include(EXT_SOURCES)
66
+
67
+ # Ruby library code.
68
+ LIB_FILES = FileList["lib/**/*.rb"]
69
+
70
+ # Filelist with Test::Unit test cases.
71
+ TEST_FILES = FileList["tests/**/tc_*.rb"]
72
+
73
+ # Executable scripts, all non-garbage files under bin/.
74
+ BIN_FILES = FileList["bin/*"]
75
+
76
+ # This filelist is used to create source packages.
77
+ # Include all Ruby and RDoc files.
78
+ DIST_FILES = FileList["**/*.rb", "**/*.rdoc"]
79
+ DIST_FILES.include("Rakefile", "COPYING")
80
+ DIST_FILES.include(BIN_FILES)
81
+ DIST_FILES.include("data/**/*", "test/data/**/*")
82
+ DIST_FILES.include("#{WEBSITE_DIR}/**/*.{html,css}", "man/*.[0-9]")
83
+ # Don't package files which are autogenerated by RDocTask
84
+ DIST_FILES.exclude(/^(\.\/)?#{RDOC_HTML_DIR}(\/|$)/)
85
+ # Include extension source files.
86
+ DIST_FILES.include(EXT_DIST_FILES)
87
+ # Don't package temporary files, perhaps created by tests.
88
+ DIST_FILES.exclude("**/temp_*", "**/*.tmp")
89
+ # Don't get into recursion...
90
+ DIST_FILES.exclude(/^(\.\/)?pkg(\/|$)/)
91
+ # Don't bring in our DARCS tree.
92
+ DIST_FILES.exclude(/^(\.\/)?_darcs(\/|$)/)
93
+ # Include our documentation/sample files.
94
+ DIST_FILES.include("docs/**/*")
95
+ #---
96
+ # Run the tests if rake is invoked without arguments.
97
+ task "default" => ["test"]
98
+
99
+ test_task_name = HAVE_EXT ? "run-tests" : "test"
100
+ Rake::TestTask.new(test_task_name) do |t|
101
+ t.test_files = TEST_FILES
102
+ t.libs = REQUIRE_PATHS
103
+ end
104
+ #---
105
+ # Set an environment variable with any configuration options you want to
106
+ # be passed through to "setup.rb config".
107
+ CONFIG_OPTS = ENV["CONFIG"]
108
+ if HAVE_EXT
109
+ file_create ".config" do
110
+ ruby "setup.rb config #{CONFIG_OPTS}"
111
+ end
112
+
113
+ desc "Configure and make extension. " +
114
+ "The CONFIG variable is passed to `setup.rb config'"
115
+ task "make-ext" => ".config" do
116
+ # The -q option suppresses messages from setup.rb.
117
+ ruby "setup.rb -q setup"
118
+ end
119
+
120
+ desc "Run tests after making the extension."
121
+ task "test" do
122
+ Rake::Task["make-ext"].invoke
123
+ Rake::Task["run-tests"].invoke
124
+ end
125
+ end
126
+ #---
127
+ # The "rdoc" task generates API documentation.
128
+ Rake::RDocTask.new("rdoc") do |t|
129
+ t.rdoc_files = RDOC_FILES + LIB_FILES
130
+ t.title = GENERAL_RDOC_OPTS["--title"]
131
+ t.main = GENERAL_RDOC_OPTS["--main"]
132
+ t.rdoc_dir = RDOC_HTML_DIR
133
+ end
134
+ #---
135
+ GEM_SPEC = Gem::Specification.new do |s|
136
+ s.name = UNIX_NAME
137
+ s.version = PROJECT_VERSION
138
+ s.summary = PROJECT_SUMMARY
139
+ s.rubyforge_project = UNIX_NAME
140
+ s.homepage = "http://#{UNIX_NAME}.rubyforge.org/"
141
+ s.author = MY_NAME
142
+ s.email = MY_EMAIL
143
+ s.files = DIST_FILES
144
+ s.test_files = TEST_FILES
145
+ s.executables = BIN_FILES.map { |fn| File.basename(fn) }
146
+ s.has_rdoc = true
147
+ s.extra_rdoc_files = RDOC_FILES
148
+ s.rdoc_options = GENERAL_RDOC_OPTS.to_a.flatten
149
+ if HAVE_EXT
150
+ s.extensions = EXTCONF_FILES
151
+ s.require_paths << EXT_DIR
152
+ end
153
+ end
154
+
155
+ # Now we can generate the package-related tasks.
156
+ Rake::GemPackageTask.new(GEM_SPEC) do |pkg|
157
+ pkg.need_zip = true
158
+ pkg.need_tar = true
159
+ end
160
+ #---
161
+ desc "Upload website to RubyForge. " +
162
+ "scp will prompt for your RubyForge password."
163
+ task "publish-website" => ["rdoc"] do
164
+ rubyforge_path = "/var/www/gforge-projects/#{UNIX_NAME}/"
165
+ sh "scp -r #{WEBSITE_DIR}/* " +
166
+ "#{RUBYFORGE_USER}@rubyforge.org:#{rubyforge_path}",
167
+ :verbose => true
168
+ end
169
+ #---
170
+ task "rubyforge-setup" do
171
+ unless File.exist?(File.join(ENV["HOME"], ".rubyforge"))
172
+ puts "rubyforge will ask you to edit its config.yml now."
173
+ puts "Please set the `username' and `password' entries"
174
+ puts "to your RubyForge username and RubyForge password!"
175
+ puts "Press ENTER to continue."
176
+ $stdin.gets
177
+ sh "rubyforge setup", :verbose => true
178
+ end
179
+ end
180
+
181
+ task "rubyforge-login" => ["rubyforge-setup"] do
182
+ # Note: We assume that username and password were set in
183
+ # rubyforge's config.yml.
184
+ sh "rubyforge login", :verbose => true
185
+ end
186
+
187
+ task "publish-packages" => ["package", "rubyforge-login"] do
188
+ # Upload packages under pkg/ to RubyForge
189
+ # This task makes some assumptions:
190
+ # * You have already created a package on the "Files" tab on the
191
+ # RubyForge project page. See pkg_name variable below.
192
+ # * You made entries under package_ids and group_ids for this
193
+ # project in rubyforge's config.yml. If not, eventually read
194
+ # "rubyforge --help" and then run "rubyforge setup".
195
+ pkg_name = ENV["PKG_NAME"] || UNIX_NAME
196
+ cmd = "rubyforge add_release #{UNIX_NAME} #{pkg_name} " +
197
+ "#{PROJECT_VERSION} #{UNIX_NAME}-#{PROJECT_VERSION}"
198
+ cd "pkg" do
199
+ sh(cmd + ".gem", :verbose => true)
200
+ sh(cmd + ".tgz", :verbose => true)
201
+ sh(cmd + ".zip", :verbose => true)
202
+ end
203
+ end
204
+ #---
205
+ # The "prepare-release" task makes sure your tests run, and then generates
206
+ # files for a new release.
207
+ desc "Run tests, generate RDoc and create packages."
208
+ task "prepare-release" => ["clobber"] do
209
+ puts "Preparing release of #{PROJECT} version #{VERSION}"
210
+ Rake::Task["test"].invoke
211
+ Rake::Task["rdoc"].invoke
212
+ Rake::Task["package"].invoke
213
+ end
214
+
215
+ # The "publish" task is the overarching task for the whole project. It
216
+ # builds a release and then publishes it to RubyForge.
217
+ desc "Publish new release of #{PROJECT}"
218
+ task "publish" => ["prepare-release"] do
219
+ puts "Uploading documentation..."
220
+ Rake::Task["publish-website"].invoke
221
+ puts "Checking for rubyforge command..."
222
+ `rubyforge --help`
223
+ if $? == 0
224
+ puts "Uploading packages..."
225
+ Rake::Task["publish-packages"].invoke
226
+ puts "Release done!"
227
+ else
228
+ puts "Can't invoke rubyforge command."
229
+ puts "Either install rubyforge with 'gem install rubyforge'"
230
+ puts "and retry or upload the package files manually!"
231
+ end
232
+ end
233
+ =begin
234
+ #---
235
+ $ rake -T
236
+ rake clean # Remove any temporary products.
237
+ rake clobber # Remove any generated file.
238
+ rake clobber_package # Remove package products
239
+ rake clobber_rdoc # Remove rdoc products
240
+ rake package # Build all the packages
241
+ rake prepare-release # Run tests, generate RDoc and create packages.
242
+ rake publish # Publish new release of MyProject
243
+ rake publish-website # Upload website to RubyForge. scp will prompt for your RubyForge password.
244
+ rake rdoc # Build the rdoc HTML Files
245
+ rake repackage # Force a rebuild of the package files
246
+ rake rerdoc # Force a rebuild of the RDOC files
247
+ rake test # Run tests for test
248
+ #---
249
+ =end
@@ -0,0 +1,4 @@
1
+ = TODO
2
+ 1. Supply formal unit tests.
3
+ 2. Provide XHTML weaving support.
4
+ 3. Design generic weaving framework.
@@ -0,0 +1,115 @@
1
+ #! /usr/bin/ruby -w
2
+
3
+ # RTANGLE -- External tangling tool for literate Ruby.
4
+ # Copyright (C) 2007 Michael T. Richter <ttmrichter@gmail.com>
5
+ #
6
+ # This program is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation; Version 2, June 1991 (and no other).
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program (in the file COPYING); if not, write to the Free
17
+ # Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
18
+ # USA
19
+
20
+ require 'rubygems'
21
+ require 'rweb'
22
+
23
+ eval RWEB.tangle(DATA)
24
+
25
+ __END__
26
+ {title => RTANGLE}
27
+
28
+ This is a simple utility that acts as a wrapper around RWEB's tangle and,
29
+ instead of executing the resulting code, either prints it to stdout or saves it
30
+ to a given file. Note that RTangle is itself written in RWEB's executable format
31
+ with the boilerplate before the __END__ statement and the actual program
32
+ document afterwards.
33
+
34
+ The mainline code is quite simple:
35
+
36
+ << {
37
+ {<<global requires>>}
38
+
39
+ {<<command line processing>>}
40
+
41
+ {<<tangling>>}
42
+
43
+ {<<main>>}
44
+ }>>
45
+
46
+ The only require we need to introduce is to require RWEB itself. This is not, of
47
+ course, necessary if we execute the RWEB document directly. Since, however, it
48
+ is highly likely that we may at some point wish to tangle the RTangle utility
49
+ itself into a Ruby source file, we should, pro forma, require the library
50
+ anyway.
51
+
52
+ << global requires {
53
+ require 'rweb'
54
+ }>>
55
+
56
+ The tangling stage itself is a very simple function which takes any kind of IO
57
+ object for input, tangles it, then places the resulting string into the output,
58
+ itself an IO object of any kind. It also doesn't care in the slightest exactly
59
+ what kind of IO object is being used, thus suited to application as a filter in
60
+ a potentially longer chain of tools.
61
+
62
+ << tangling {
63
+ def rtangle(io_in, io_out)
64
+ io_out << RWEB.tangle(io_in)
65
+ end
66
+ }>>
67
+
68
+ As can be seen, the true heavy lifting is done inside of the RWEB module. This
69
+ utility is a hyper-simple shell around it by comparison.
70
+
71
+ The mainline function is pretty simple as well. It just takes the arguments from
72
+ the command line and passes them to the command line processor blindly,
73
+ accepting in return a pair of IO objects -- one for input, the other for output.
74
+ It then calls tangle with these objects, wrapping in a begin/ensure clause to
75
+ make sure the IO objects are closed before exiting. The only additional step it
76
+ takes is a call to the function find_block_begin which shadows the IO object
77
+ used for input and silently sweeps away the stuff before __END__ in a document
78
+ if it exists in the first 20 lines.
79
+
80
+ << main {
81
+ io_in, io_out = process_argv ARGV
82
+ begin
83
+ rtangle(io_in, io_out)
84
+ ensure
85
+ io_in.close
86
+ io_out.close
87
+ end
88
+ }>>
89
+
90
+ All that's left is the command line processor.
91
+
92
+ << command line processing {
93
+ def process_argv args
94
+ io_in = STDIN
95
+ io_out = STDOUT
96
+ if args.length > 2
97
+ {<<display usage>>}
98
+ end
99
+ arg = args.shift
100
+ io_in = File.open(arg, "r") if arg
101
+ arg = args.shift
102
+ io_out = File.open(arg, "w") if arg
103
+ return io_in, io_out
104
+ end
105
+ }>>
106
+
107
+ The usage message is straightforward and broken out only to reduce code clutter.
108
+
109
+ << display usage {
110
+ puts "Incorrect command line."
111
+ puts "Usage:"
112
+ puts " rtangle [input_file [output_file]]"
113
+ puts
114
+ puts "Files default to stdin and stdout respectively."
115
+ }>>
@@ -0,0 +1,115 @@
1
+ #! /usr/bin/ruby -w
2
+
3
+ # RWEAVE -- External weaving tool for literate Ruby.
4
+ # Copyright (C) 2007 Michael T. Richter <ttmrichter@gmail.com>
5
+ #
6
+ # This program is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation; Version 2, June 1991 (and no other).
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program (in the file COPYING.txt); if not, write to the Free
17
+ # Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
18
+ # USA
19
+
20
+ require 'rubygems'
21
+ require 'rweb'
22
+
23
+ eval RWEB.tangle(DATA)
24
+
25
+ __END__
26
+ {title => RWEAVE}
27
+
28
+ This is a simple utility that acts as a wrapper around RWEB's weave and, instead
29
+ of executing the resulting code, either prints it to stdout or saves it to a
30
+ given file. Note that RWeave is itself written in RWEB's executable format with
31
+ the boilerplate before the __END__ statement and the actual program document
32
+ afterwards.
33
+
34
+ The mainline code is quite simple:
35
+
36
+ << {
37
+ {<<global requires>>}
38
+
39
+ {<<command line processing>>}
40
+
41
+ {<<weaving>>}
42
+
43
+ {<<main>>}
44
+ }>>
45
+
46
+ The only require we need to introduce is to require RWEB itself. This is not, of
47
+ course, necessary if we execute the RWEB document directly. Since, however, it
48
+ is highly likely that we may at some point wish to weave the RWeave utility
49
+ itself into a Ruby source file, we should, pro forma, require the library
50
+ anyway.
51
+
52
+ << global requires {
53
+ require 'rweb'
54
+ }>>
55
+
56
+ The weaving stage itself is a very simple function which takes any kind of IO
57
+ object for input, weaves it, then places the resulting string into the output,
58
+ itself an IO object of any kind. It also doesn't care in the slightest exactly
59
+ what kind of IO object is being used, thus suited to application as a filter in
60
+ a potentially longer chain of tools.
61
+
62
+ << weaving {
63
+ def rweave(io_in, io_out)
64
+ io_out << RWEB.weave(io_in)
65
+ end
66
+ }>>
67
+
68
+ As can be seen, the true heavy lifting is done inside of the RWEB module. This
69
+ utility is a hyper-simple shell around it by comparison.
70
+
71
+ The mainline function is pretty simple as well. It just takes the arguments from
72
+ the command line and passes them to the command line processor blindly,
73
+ accepting in return a pair of IO objects -- one for input, the other for output.
74
+ It then calls weave with these objects, wrapping in a begin/ensure clause to
75
+ make sure the IO objects are closed before exiting. The only additional step it
76
+ takes is a call to the function find_block_begin which shadows the IO object
77
+ used for input and silently sweeps away the stuff before __END__ in a document
78
+ if it exists in the first 20 lines.
79
+
80
+ << main {
81
+ io_in, io_out = process_argv ARGV
82
+ begin
83
+ rweave(io_in, io_out)
84
+ ensure
85
+ io_in.close
86
+ io_out.close
87
+ end
88
+ }>>
89
+
90
+ All that's left is the command line processor.
91
+
92
+ << command line processing {
93
+ def process_argv args
94
+ io_in = STDIN
95
+ io_out = STDOUT
96
+ if args.length > 2
97
+ {<<display usage>>}
98
+ end
99
+ arg = args.shift
100
+ io_in = File.open(arg, "r") if arg
101
+ arg = args.shift
102
+ io_out = File.open(arg, "w") if arg
103
+ return io_in, io_out
104
+ end
105
+ }>>
106
+
107
+ The usage message is straightforward and broken out only to reduce code clutter.
108
+
109
+ << display usage {
110
+ puts "Incorrect command line."
111
+ puts "Usage:"
112
+ puts " rweave [input_file [output_file]]"
113
+ puts
114
+ puts "Files default to stdin and stdout respectively."
115
+ }>>