mirror of
https://github.com/elastic/logstash.git
synced 2025-04-24 14:47:19 -04:00
- Add logstash web frontend. This is a Merb application.
This commit is contained in:
parent
0061adadc3
commit
cf8ee9b312
55 changed files with 7401 additions and 0 deletions
21
web/.gitignore
vendored
Normal file
21
web/.gitignore
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
.DS_Store
|
||||
log/*
|
||||
tmp/*
|
||||
TAGS
|
||||
*~
|
||||
.#*
|
||||
schema/schema.rb
|
||||
schema/*_structure.sql
|
||||
schema/*.sqlite3
|
||||
schema/*.sqlite
|
||||
schema/*.db
|
||||
*.sqlite
|
||||
*.sqlite3
|
||||
*.db
|
||||
src/*
|
||||
.hgignore
|
||||
.hg/*
|
||||
.svn/*
|
||||
gems/gems/*
|
||||
gems/specifications/*
|
||||
merb_profile_results
|
35
web/Rakefile
Normal file
35
web/Rakefile
Normal file
|
@ -0,0 +1,35 @@
|
|||
require 'rubygems'
|
||||
require 'rake/rdoctask'
|
||||
|
||||
require 'merb-core'
|
||||
require 'merb-core/tasks/merb'
|
||||
|
||||
include FileUtils
|
||||
|
||||
# Load the basic runtime dependencies; this will include
|
||||
# any plugins and therefore plugin rake tasks.
|
||||
init_env = ENV['MERB_ENV'] || 'rake'
|
||||
Merb.load_dependencies(:environment => init_env)
|
||||
|
||||
# Get Merb plugins and dependencies
|
||||
Merb::Plugins.rakefiles.each { |r| require r }
|
||||
|
||||
# Load any app level custom rakefile extensions from lib/tasks
|
||||
tasks_path = File.join(File.dirname(__FILE__), "lib", "tasks")
|
||||
rake_files = Dir["#{tasks_path}/*.rake"]
|
||||
rake_files.each{|rake_file| load rake_file }
|
||||
|
||||
desc "Start runner environment"
|
||||
task :merb_env do
|
||||
Merb.start_environment(:environment => init_env, :adapter => 'runner')
|
||||
end
|
||||
|
||||
require 'spec/rake/spectask'
|
||||
require 'merb-core/test/tasks/spectasks'
|
||||
desc 'Default: run spec examples'
|
||||
task :default => 'spec'
|
||||
|
||||
##############################################################################
|
||||
# ADD YOUR CUSTOM TASKS IN /lib/tasks
|
||||
# NAME YOUR RAKE FILES file_name.rake
|
||||
##############################################################################
|
2
web/app/controllers/application.rb
Normal file
2
web/app/controllers/application.rb
Normal file
|
@ -0,0 +1,2 @@
|
|||
class Application < Merb::Controller
|
||||
end
|
13
web/app/controllers/exceptions.rb
Normal file
13
web/app/controllers/exceptions.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
class Exceptions < Merb::Controller
|
||||
|
||||
# handle NotFound exceptions (404)
|
||||
def not_found
|
||||
render :format => :html
|
||||
end
|
||||
|
||||
# handle NotAcceptable exceptions (406)
|
||||
def not_acceptable
|
||||
render :format => :html
|
||||
end
|
||||
|
||||
end
|
57
web/app/controllers/search.rb
Normal file
57
web/app/controllers/search.rb
Normal file
|
@ -0,0 +1,57 @@
|
|||
|
||||
$: << ".."
|
||||
require "lib/net/client"
|
||||
require "lib/net/messages/search"
|
||||
require "lib/net/messages/searchhits"
|
||||
require "lib/net/messages/ping"
|
||||
require "timeout"
|
||||
|
||||
class SearchClient < LogStash::Net::MessageClient
|
||||
attr_reader :results
|
||||
attr_reader :hits
|
||||
|
||||
def SearchHitsResponseHandler(msg)
|
||||
@hits = msg.hits
|
||||
end
|
||||
|
||||
def SearchResponseHandler(msg)
|
||||
if @results == nil
|
||||
@results = []
|
||||
end
|
||||
|
||||
msg.results.each do |result|
|
||||
@results << result
|
||||
end
|
||||
|
||||
if msg.finished
|
||||
close
|
||||
end
|
||||
end # def SearchResponseHandler
|
||||
end # class SearchClient
|
||||
|
||||
class Search < Application
|
||||
|
||||
def index
|
||||
render
|
||||
end
|
||||
|
||||
def query
|
||||
@searchclient = SearchClient.new(host="localhost", port=61613)
|
||||
msg = LogStash::Net::Messages::SearchHitsRequest.new
|
||||
msg.log_type = (params[:log_type] or "linux-syslog")
|
||||
msg.query = params[:q]
|
||||
@searchclient.sendmsg("/queue/logstash", msg)
|
||||
|
||||
msg = LogStash::Net::Messages::SearchRequest.new
|
||||
msg.log_type = (params[:log_type] or "linux-syslog")
|
||||
msg.query = params[:q]
|
||||
msg.limit = 20
|
||||
@searchclient.sendmsg("/queue/logstash", msg)
|
||||
|
||||
Timeout.timeout(10) do
|
||||
@searchclient.run
|
||||
render
|
||||
end
|
||||
end
|
||||
|
||||
end
|
5
web/app/helpers/global_helpers.rb
Normal file
5
web/app/helpers/global_helpers.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
module Merb
|
||||
module GlobalHelpers
|
||||
# helpers defined here available to all views.
|
||||
end
|
||||
end
|
5
web/app/helpers/search_helper.rb
Normal file
5
web/app/helpers/search_helper.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
module Merb
|
||||
module SearchHelper
|
||||
|
||||
end
|
||||
end # Merb
|
17
web/app/models/user.rb
Normal file
17
web/app/models/user.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
# This is a default user class used to activate merb-auth. Feel free to change from a User to
|
||||
# Some other class, or to remove it altogether. If removed, merb-auth may not work by default.
|
||||
#
|
||||
# Don't forget that by default the salted_user mixin is used from merb-more
|
||||
# You'll need to setup your db as per the salted_user mixin, and you'll need
|
||||
# To use :password, and :password_confirmation when creating a user
|
||||
#
|
||||
# see merb/merb-auth/setup.rb to see how to disable the salted_user mixin
|
||||
#
|
||||
# You will need to setup your database and create a user.
|
||||
class User
|
||||
include DataMapper::Resource
|
||||
|
||||
property :id, Serial
|
||||
property :login, String
|
||||
|
||||
end
|
63
web/app/views/exceptions/not_acceptable.html.erb
Normal file
63
web/app/views/exceptions/not_acceptable.html.erb
Normal file
|
@ -0,0 +1,63 @@
|
|||
<div id="container">
|
||||
<div id="header-container">
|
||||
<img src="/images/merb.jpg" />
|
||||
<!-- <h1>Mongrel + Erb</h1> -->
|
||||
<h2>pocket rocket web framework</h2>
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div id="left-container">
|
||||
<h3>Exception:</h3>
|
||||
<p><%= request.exceptions.first.message %></p>
|
||||
</div>
|
||||
|
||||
<div id="main-container">
|
||||
<h3>Why am I seeing this page?</h3>
|
||||
<p>Merb couldn't find an appropriate content_type to return,
|
||||
based on what you said was available via provides() and
|
||||
what the client requested.</p>
|
||||
|
||||
<h3>How to add a mime-type</h3>
|
||||
<pre><code>
|
||||
Merb.add_mime_type :pdf, :to_pdf, %w[application/pdf], "Content-Encoding" => "gzip"
|
||||
</code></pre>
|
||||
<h3>What this means is:</h3>
|
||||
<ul>
|
||||
<li>Add a mime-type for :pdf</li>
|
||||
<li>Register the method for converting objects to PDF as <code>#to_pdf</code>.</li>
|
||||
<li>Register the incoming mime-type "Accept" header as <code>application/pdf</code>.</li>
|
||||
<li>Specify a new header for PDF types so it will set <code>Content-Encoding</code> to gzip.</li>
|
||||
</ul>
|
||||
|
||||
<h3>You can then do:</h3>
|
||||
<pre><code>
|
||||
class Foo < Application
|
||||
provides :pdf
|
||||
end
|
||||
</code></pre>
|
||||
|
||||
<h3>Where can I find help?</h3>
|
||||
<p>If you have any questions or if you can't figure something out, please take a
|
||||
look at our <a href="http://merbivore.com/"> project page</a>,
|
||||
feel free to come chat at irc.freenode.net, channel #merb,
|
||||
or post to <a href="http://groups.google.com/group/merb">merb mailing list</a>
|
||||
on Google Groups.</p>
|
||||
|
||||
<h3>What if I've found a bug?</h3>
|
||||
<p>If you want to file a bug or make your own contribution to Merb,
|
||||
feel free to register and create a ticket at our
|
||||
<a href="http://merb.lighthouseapp.com/">project development page</a>
|
||||
on Lighthouse.</p>
|
||||
|
||||
<h3>How do I edit this page?</h3>
|
||||
<p>You can change what people see when this happens by editing <tt>app/views/exceptions/not_acceptable.html.erb</tt>.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="footer-container">
|
||||
<hr />
|
||||
<div class="left"></div>
|
||||
<div class="right">© 2008 the merb dev team</div>
|
||||
<p> </p>
|
||||
</div>
|
||||
</div>
|
47
web/app/views/exceptions/not_found.html.erb
Normal file
47
web/app/views/exceptions/not_found.html.erb
Normal file
|
@ -0,0 +1,47 @@
|
|||
<div id="container">
|
||||
<div id="header-container">
|
||||
<img src="/images/merb.jpg" />
|
||||
<!-- <h1>Mongrel + Erb</h1> -->
|
||||
<h2>pocket rocket web framework</h2>
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div id="left-container">
|
||||
<h3>Exception:</h3>
|
||||
<p><%= request.exceptions.first.message %></p>
|
||||
</div>
|
||||
|
||||
<div id="main-container">
|
||||
<h3>Welcome to Merb!</h3>
|
||||
<p>Merb is a light-weight MVC framework written in Ruby. We hope you enjoy it.</p>
|
||||
|
||||
<h3>Where can I find help?</h3>
|
||||
<p>If you have any questions or if you can't figure something out, please take a
|
||||
look at our <a href="http://merbivore.com/"> project page</a>,
|
||||
feel free to come chat at irc.freenode.net, channel #merb,
|
||||
or post to <a href="http://groups.google.com/group/merb">merb mailing list</a>
|
||||
on Google Groups.</p>
|
||||
|
||||
<h3>What if I've found a bug?</h3>
|
||||
<p>If you want to file a bug or make your own contribution to Merb,
|
||||
feel free to register and create a ticket at our
|
||||
<a href="http://merb.lighthouseapp.com/">project development page</a>
|
||||
on Lighthouse.</p>
|
||||
|
||||
<h3>How do I edit this page?</h3>
|
||||
<p>You're seeing this page because you need to edit the following files:
|
||||
<ul>
|
||||
<li>config/router.rb <strong><em>(recommended)</em></strong></li>
|
||||
<li>app/views/exceptions/not_found.html.erb <strong><em>(recommended)</em></strong></li>
|
||||
<li>app/views/layout/application.html.erb <strong><em>(change this layout)</em></strong></li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div id="footer-container">
|
||||
<hr />
|
||||
<div class="left"></div>
|
||||
<div class="right">© 2008 the merb dev team</div>
|
||||
<p> </p>
|
||||
</div>
|
||||
</div>
|
12
web/app/views/layout/application.html.erb
Normal file
12
web/app/views/layout/application.html.erb
Normal file
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-us" lang="en-us">
|
||||
<head>
|
||||
<title>Fresh Merb App</title>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<link rel="stylesheet" href="/stylesheets/master.css" type="text/css" media="screen" charset="utf-8" />
|
||||
</head>
|
||||
<body>
|
||||
<%#= message[:notice] %>
|
||||
<%= catch_content :for_layout %>
|
||||
</body>
|
||||
</html>
|
4
web/app/views/search/index.html.erb
Normal file
4
web/app/views/search/index.html.erb
Normal file
|
@ -0,0 +1,4 @@
|
|||
<%= form :action => url(:controller => "search", :action => "query") do %>
|
||||
<%= text_field :name => "q", :label => "Query" %>
|
||||
<%= submit "Search" %>
|
||||
<% end =%>
|
12
web/app/views/search/query.html.erb
Normal file
12
web/app/views/search/query.html.erb
Normal file
|
@ -0,0 +1,12 @@
|
|||
<%= form :action => url(:controller => "search", :action => "query") do %>
|
||||
<%= text_field :name => "q", :label => "Query", :value => escape_html(params[:q]) %>
|
||||
<%= submit "Search" %>
|
||||
<% end =%>
|
||||
|
||||
<hr>
|
||||
|
||||
<h4>Hits: <%= @searchclient.hits %></h4>
|
||||
<hr>
|
||||
<pre>
|
||||
<%=h @searchclient.results.join("\n") %>
|
||||
</pre>
|
2
web/autotest/discover.rb
Normal file
2
web/autotest/discover.rb
Normal file
|
@ -0,0 +1,2 @@
|
|||
Autotest.add_discovery { "merb" }
|
||||
Autotest.add_discovery { "rspec" }
|
152
web/autotest/merb.rb
Normal file
152
web/autotest/merb.rb
Normal file
|
@ -0,0 +1,152 @@
|
|||
# Adapted from Autotest::Rails
|
||||
require 'autotest'
|
||||
|
||||
class Autotest::Merb < Autotest
|
||||
|
||||
# +model_tests_dir+:: the directory to find model-centric tests
|
||||
# +controller_tests_dir+:: the directory to find controller-centric tests
|
||||
# +view_tests_dir+:: the directory to find view-centric tests
|
||||
# +fixtures_dir+:: the directory to find fixtures in
|
||||
attr_accessor :model_tests_dir, :controller_tests_dir, :view_tests_dir, :fixtures_dir
|
||||
|
||||
def initialize
|
||||
super
|
||||
|
||||
initialize_test_layout
|
||||
|
||||
# Ignore any happenings in these directories
|
||||
add_exception %r%^\./(?:doc|log|public|tmp|\.git|\.hg|\.svn|framework|gems|schema|\.DS_Store|autotest|bin|.*\.sqlite3)%
|
||||
# Ignore SCM directories and custom Autotest mappings
|
||||
%w[.svn .hg .git .autotest].each { |exception| add_exception(exception) }
|
||||
|
||||
|
||||
# Ignore any mappings that Autotest may have already set up
|
||||
clear_mappings
|
||||
|
||||
# Any changes to a file in the root of the 'lib' directory will run any
|
||||
# model test with a corresponding name.
|
||||
add_mapping %r%^lib\/.*\.rb% do |filename, _|
|
||||
files_matching Regexp.new(["^#{model_test_for(filename)}$"])
|
||||
end
|
||||
|
||||
# Any changes to a fixture will run corresponding view, controller and
|
||||
# model tests
|
||||
add_mapping %r%^#{fixtures_dir}/(.*)s.yml% do |_, m|
|
||||
[
|
||||
model_test_for(m[1]),
|
||||
controller_test_for(m[1]),
|
||||
view_test_for(m[1])
|
||||
]
|
||||
end
|
||||
|
||||
# Any change to a test will cause it to be run
|
||||
add_mapping %r%^test/(unit|models|integration|controllers|views|functional)/.*rb$% do |filename, _|
|
||||
filename
|
||||
end
|
||||
|
||||
# Any change to a model will cause it's corresponding test to be run
|
||||
add_mapping %r%^app/models/(.*)\.rb$% do |_, m|
|
||||
model_test_for(m[1])
|
||||
end
|
||||
|
||||
# Any change to the global helper will result in all view and controller
|
||||
# tests being run
|
||||
add_mapping %r%^app/helpers/global_helpers.rb% do
|
||||
files_matching %r%^test/(views|functional|controllers)/.*_test\.rb$%
|
||||
end
|
||||
|
||||
# Any change to a helper will run it's corresponding view and controller
|
||||
# tests, unless the helper is the global helper. Changes to the global
|
||||
# helper run all view and controller tests.
|
||||
add_mapping %r%^app/helpers/(.*)_helper(s)?.rb% do |_, m|
|
||||
if m[1] == "global" then
|
||||
files_matching %r%^test/(views|functional|controllers)/.*_test\.rb$%
|
||||
else
|
||||
[
|
||||
view_test_for(m[1]),
|
||||
controller_test_for(m[1])
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
# Changes to views result in their corresponding view and controller test
|
||||
# being run
|
||||
add_mapping %r%^app/views/(.*)/% do |_, m|
|
||||
[
|
||||
view_test_for(m[1]),
|
||||
controller_test_for(m[1])
|
||||
]
|
||||
end
|
||||
|
||||
# Changes to a controller result in its corresponding test being run. If
|
||||
# the controller is the exception or application controller, all
|
||||
# controller tests are run.
|
||||
add_mapping %r%^app/controllers/(.*)\.rb$% do |_, m|
|
||||
if ["application", "exception"].include?(m[1])
|
||||
files_matching %r%^test/(controllers|views|functional)/.*_test\.rb$%
|
||||
else
|
||||
controller_test_for(m[1])
|
||||
end
|
||||
end
|
||||
|
||||
# If a change is made to the router, run all controller and view tests
|
||||
add_mapping %r%^config/router.rb$% do # FIX
|
||||
files_matching %r%^test/(controllers|views|functional)/.*_test\.rb$%
|
||||
end
|
||||
|
||||
# If any of the major files governing the environment are altered, run
|
||||
# everything
|
||||
add_mapping %r%^test/test_helper.rb|config/(init|rack|environments/test.rb|database.yml)% do # FIX
|
||||
files_matching %r%^test/(unit|models|controllers|views|functional)/.*_test\.rb$%
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Determines the paths we can expect tests or specs to reside, as well as
|
||||
# corresponding fixtures.
|
||||
def initialize_test_layout
|
||||
self.model_tests_dir = "test/unit"
|
||||
self.controller_tests_dir = "test/functional"
|
||||
self.view_tests_dir = "test/views"
|
||||
self.fixtures_dir = "test/fixtures"
|
||||
end
|
||||
|
||||
# Given a filename and the test type, this method will return the
|
||||
# corresponding test's or spec's name.
|
||||
#
|
||||
# ==== Arguments
|
||||
# +filename+<String>:: the file name of the model, view, or controller
|
||||
# +kind_of_test+<Symbol>:: the type of test we that we should run
|
||||
#
|
||||
# ==== Returns
|
||||
# String:: the name of the corresponding test or spec
|
||||
#
|
||||
# ==== Example
|
||||
#
|
||||
# > test_for("user", :model)
|
||||
# => "user_test.rb"
|
||||
# > test_for("login", :controller)
|
||||
# => "login_controller_test.rb"
|
||||
# > test_for("form", :view)
|
||||
# => "form_view_spec.rb" # If you're running a RSpec-like suite
|
||||
def test_for(filename, kind_of_test)
|
||||
name = [filename]
|
||||
name << kind_of_test.to_s if kind_of_test == :view
|
||||
name << "test"
|
||||
return name.join("_") + ".rb"
|
||||
end
|
||||
|
||||
def model_test_for(filename)
|
||||
[model_tests_dir, test_for(filename, :model)].join("/")
|
||||
end
|
||||
|
||||
def controller_test_for(filename)
|
||||
[controller_tests_dir, test_for(filename, :controller)].join("/")
|
||||
end
|
||||
|
||||
def view_test_for(filename)
|
||||
[view_tests_dir, test_for(filename, :view)].join("/")
|
||||
end
|
||||
|
||||
end
|
165
web/autotest/merb_rspec.rb
Normal file
165
web/autotest/merb_rspec.rb
Normal file
|
@ -0,0 +1,165 @@
|
|||
# Adapted from Autotest::Rails, RSpec's autotest class, as well as merb-core's.
|
||||
require 'autotest'
|
||||
|
||||
class RspecCommandError < StandardError; end
|
||||
|
||||
# This class maps your application's structure so Autotest can understand what
|
||||
# specs to run when files change.
|
||||
#
|
||||
# Fixtures are _not_ covered by this class. If you change a fixture file, you
|
||||
# will have to run your spec suite manually, or, better yet, provide your own
|
||||
# Autotest map explaining how your fixtures are set up.
|
||||
class Autotest::MerbRspec < Autotest
|
||||
def initialize
|
||||
super
|
||||
|
||||
# Ignore any happenings in these directories
|
||||
add_exception %r%^\./(?:doc|log|public|tmp|\.git|\.hg|\.svn|framework|gems|schema|\.DS_Store|autotest|bin|.*\.sqlite3|.*\.thor)%
|
||||
# Ignore SCM directories and custom Autotest mappings
|
||||
%w[.svn .hg .git .autotest].each { |exception| add_exception(exception) }
|
||||
|
||||
# Ignore any mappings that Autotest may have already set up
|
||||
clear_mappings
|
||||
|
||||
# Anything in /lib could have a spec anywhere, if at all. So, look for
|
||||
# files with roughly the same name as the file in /lib
|
||||
add_mapping %r%^lib\/(.*)\.rb% do |_, m|
|
||||
files_matching %r%^spec\/#{m[1]}%
|
||||
end
|
||||
|
||||
add_mapping %r%^spec/(spec_helper|shared/.*)\.rb$% do
|
||||
all_specs
|
||||
end
|
||||
|
||||
# Changing a spec will cause it to run itself
|
||||
add_mapping %r%^spec/.*\.rb$% do |filename, _|
|
||||
filename
|
||||
end
|
||||
|
||||
# Any change to a model will cause it's corresponding test to be run
|
||||
add_mapping %r%^app/models/(.*)\.rb$% do |_, m|
|
||||
spec_for(m[1], 'model')
|
||||
end
|
||||
|
||||
# Any change to global_helpers will result in all view and controller
|
||||
# tests being run
|
||||
add_mapping %r%^app/helpers/global_helpers\.rb% do
|
||||
files_matching %r%^spec/(views|controllers|helpers|requests)/.*_spec\.rb$%
|
||||
end
|
||||
|
||||
# Any change to a helper will cause its spec to be run
|
||||
add_mapping %r%^app/helpers/((.*)_helper(s)?)\.rb% do |_, m|
|
||||
spec_for(m[1], 'helper')
|
||||
end
|
||||
|
||||
# Changes to a view cause its spec to be run
|
||||
add_mapping %r%^app/views/(.*)/% do |_, m|
|
||||
spec_for(m[1], 'view')
|
||||
end
|
||||
|
||||
# Changes to a controller result in its corresponding spec being run. If
|
||||
# the controller is the exception or application controller, all
|
||||
# controller specs are run.
|
||||
add_mapping %r%^app/controllers/(.*)\.rb$% do |_, m|
|
||||
if ["application", "exception"].include?(m[1])
|
||||
files_matching %r%^spec/controllers/.*_spec\.rb$%
|
||||
else
|
||||
spec_for(m[1], 'controller')
|
||||
end
|
||||
end
|
||||
|
||||
# If a change is made to the router, run controller, view and helper specs
|
||||
add_mapping %r%^config/router.rb$% do
|
||||
files_matching %r%^spec/(controllers|views|helpers)/.*_spec\.rb$%
|
||||
end
|
||||
|
||||
# If any of the major files governing the environment are altered, run
|
||||
# everything
|
||||
add_mapping %r%^config/(init|rack|environments/test).*\.rb|database\.yml% do
|
||||
all_specs
|
||||
end
|
||||
end
|
||||
|
||||
def failed_results(results)
|
||||
results.scan(/^\d+\)\n(?:\e\[\d*m)?(?:.*?Error in )?'([^\n]*)'(?: FAILED)?(?:\e\[\d*m)?\n(.*?)\n\n/m)
|
||||
end
|
||||
|
||||
def handle_results(results)
|
||||
@failures = failed_results(results)
|
||||
@files_to_test = consolidate_failures(@failures)
|
||||
@files_to_test.empty? && !$TESTING ? hook(:green) : hook(:red)
|
||||
@tainted = !@files_to_test.empty?
|
||||
end
|
||||
|
||||
def consolidate_failures(failed)
|
||||
filters = Hash.new { |h,k| h[k] = [] }
|
||||
failed.each do |spec, failed_trace|
|
||||
if f = test_files_for(failed).find { |f| f =~ /spec\// }
|
||||
filters[f] << spec
|
||||
break
|
||||
end
|
||||
end
|
||||
filters
|
||||
end
|
||||
|
||||
def make_test_cmd(specs_to_runs)
|
||||
[
|
||||
ruby,
|
||||
"-S",
|
||||
spec_command,
|
||||
add_options_if_present,
|
||||
files_to_test.keys.flatten.join(' ')
|
||||
].join(' ')
|
||||
end
|
||||
|
||||
def add_options_if_present
|
||||
File.exist?("spec/spec.opts") ? "-O spec/spec.opts " : ""
|
||||
end
|
||||
|
||||
# Finds the proper spec command to use. Precendence is set in the
|
||||
# lazily-evaluated method spec_commands. Alias + Override that in
|
||||
# ~/.autotest to provide a different spec command then the default
|
||||
# paths provided.
|
||||
def spec_command(separator=File::ALT_SEPARATOR)
|
||||
unless defined?(@spec_command)
|
||||
@spec_command = spec_commands.find { |cmd| File.exists?(cmd) }
|
||||
|
||||
raise RspecCommandError, "No spec command could be found" unless @spec_command
|
||||
|
||||
@spec_command.gsub!(File::SEPARATOR, separator) if separator
|
||||
end
|
||||
@spec_command
|
||||
end
|
||||
|
||||
# Autotest will look for spec commands in the following
|
||||
# locations, in this order:
|
||||
#
|
||||
# * default spec bin/loader installed in Rubygems
|
||||
# * any spec command found in PATH
|
||||
def spec_commands
|
||||
[File.join(Config::CONFIG['bindir'], 'spec'), 'spec']
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Runs +files_matching+ for all specs
|
||||
def all_specs
|
||||
files_matching %r%^spec/.*_spec\.rb$%
|
||||
end
|
||||
|
||||
# Generates a path to some spec given its kind and the match from a mapping
|
||||
#
|
||||
# ==== Arguments
|
||||
# match<String>:: the match from a mapping
|
||||
# kind<String>:: the kind of spec that the match represents
|
||||
#
|
||||
# ==== Returns
|
||||
# String
|
||||
#
|
||||
# ==== Example
|
||||
# > spec_for('post', :view')
|
||||
# => "spec/views/post_spec.rb"
|
||||
def spec_for(match, kind)
|
||||
File.join("spec", kind + 's', "#{match}_spec.rb")
|
||||
end
|
||||
end
|
33
web/config/database.yml
Normal file
33
web/config/database.yml
Normal file
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
# This is a sample database file for the DataMapper ORM
|
||||
development: &defaults
|
||||
# These are the settings for repository :default
|
||||
adapter: sqlite3
|
||||
database: sample_development.db
|
||||
|
||||
# Add more repositories
|
||||
# repositories:
|
||||
# repo1:
|
||||
# adapter: sqlite3
|
||||
# database: sample_1_development.db
|
||||
# repo2:
|
||||
# ...
|
||||
|
||||
test:
|
||||
<<: *defaults
|
||||
database: sample_test.db
|
||||
|
||||
# repositories:
|
||||
# repo1:
|
||||
# database: sample_1_test.db
|
||||
|
||||
production:
|
||||
<<: *defaults
|
||||
database: production.db
|
||||
|
||||
# repositories:
|
||||
# repo1:
|
||||
# database: sample_production.db
|
||||
|
||||
rake:
|
||||
<<: *defaults
|
34
web/config/dependencies.rb
Normal file
34
web/config/dependencies.rb
Normal file
|
@ -0,0 +1,34 @@
|
|||
# dependencies are generated using a strict version, don't forget to edit the dependency versions when upgrading.
|
||||
merb_gems_version = "1.0.12"
|
||||
dm_gems_version = "0.9.11"
|
||||
do_gems_version = "0.9.11"
|
||||
|
||||
# For more information about each component, please read http://wiki.merbivore.com/faqs/merb_components
|
||||
dependency "merb-core", merb_gems_version
|
||||
dependency "merb-action-args", merb_gems_version
|
||||
dependency "merb-assets", merb_gems_version
|
||||
dependency("merb-cache", merb_gems_version) do
|
||||
Merb::Cache.setup do
|
||||
register(Merb::Cache::FileStore) unless Merb.cache
|
||||
end
|
||||
end
|
||||
dependency "merb-helpers", merb_gems_version
|
||||
dependency "merb-mailer", merb_gems_version
|
||||
dependency "merb-slices", merb_gems_version
|
||||
dependency "merb-auth-core", merb_gems_version
|
||||
dependency "merb-auth-more", merb_gems_version
|
||||
dependency "merb-auth-slice-password", merb_gems_version
|
||||
dependency "merb-param-protection", merb_gems_version
|
||||
dependency "merb-exceptions", merb_gems_version
|
||||
|
||||
dependency "data_objects", do_gems_version
|
||||
dependency "do_sqlite3", do_gems_version # If using another database, replace this
|
||||
dependency "dm-core", dm_gems_version
|
||||
dependency "dm-aggregates", dm_gems_version
|
||||
dependency "dm-migrations", dm_gems_version
|
||||
dependency "dm-timestamps", dm_gems_version
|
||||
dependency "dm-types", dm_gems_version
|
||||
dependency "dm-validations", dm_gems_version
|
||||
dependency "dm-serializer", dm_gems_version
|
||||
|
||||
dependency "merb_datamapper", merb_gems_version
|
15
web/config/environments/development.rb
Normal file
15
web/config/environments/development.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
Merb.logger.info("Loaded DEVELOPMENT Environment...")
|
||||
Merb::Config.use { |c|
|
||||
c[:exception_details] = true
|
||||
c[:reload_templates] = true
|
||||
c[:reload_classes] = true
|
||||
c[:reload_time] = 0.5
|
||||
c[:ignore_tampered_cookies] = true
|
||||
c[:log_auto_flush ] = true
|
||||
c[:log_level] = :debug
|
||||
|
||||
c[:log_stream] = STDOUT
|
||||
c[:log_file] = nil
|
||||
# Or redirect logging into a file:
|
||||
# c[:log_file] = Merb.root / "log" / "development.log"
|
||||
}
|
10
web/config/environments/production.rb
Normal file
10
web/config/environments/production.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
Merb.logger.info("Loaded PRODUCTION Environment...")
|
||||
Merb::Config.use { |c|
|
||||
c[:exception_details] = false
|
||||
c[:reload_classes] = false
|
||||
c[:log_level] = :error
|
||||
|
||||
c[:log_file] = Merb.root / "log" / "production.log"
|
||||
# or redirect logger using IO handle
|
||||
# c[:log_stream] = STDOUT
|
||||
}
|
11
web/config/environments/rake.rb
Normal file
11
web/config/environments/rake.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
Merb.logger.info("Loaded RAKE Environment...")
|
||||
Merb::Config.use { |c|
|
||||
c[:exception_details] = true
|
||||
c[:reload_classes] = false
|
||||
c[:log_auto_flush ] = true
|
||||
|
||||
c[:log_stream] = STDOUT
|
||||
c[:log_file] = nil
|
||||
# Or redirect logging into a file:
|
||||
# c[:log_file] = Merb.root / "log" / "development.log"
|
||||
}
|
10
web/config/environments/staging.rb
Normal file
10
web/config/environments/staging.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
Merb.logger.info("Loaded STAGING Environment...")
|
||||
Merb::Config.use { |c|
|
||||
c[:exception_details] = false
|
||||
c[:reload_classes] = false
|
||||
c[:log_level] = :error
|
||||
|
||||
c[:log_file] = Merb.root / "log" / "staging.log"
|
||||
# or redirect logger using IO handle
|
||||
# c[:log_stream] = STDOUT
|
||||
}
|
12
web/config/environments/test.rb
Normal file
12
web/config/environments/test.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
Merb.logger.info("Loaded TEST Environment...")
|
||||
Merb::Config.use { |c|
|
||||
c[:testing] = true
|
||||
c[:exception_details] = true
|
||||
c[:log_auto_flush ] = true
|
||||
# log less in testing environment
|
||||
c[:log_level] = :error
|
||||
|
||||
#c[:log_file] = Merb.root / "log" / "test.log"
|
||||
# or redirect logger using IO handle
|
||||
c[:log_stream] = STDOUT
|
||||
}
|
24
web/config/init.rb
Normal file
24
web/config/init.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Go to http://wiki.merbivore.com/pages/init-rb
|
||||
|
||||
require 'config/dependencies.rb'
|
||||
|
||||
use_orm :datamapper
|
||||
use_test :rspec
|
||||
use_template_engine :erb
|
||||
|
||||
Merb::Config.use do |c|
|
||||
c[:use_mutex] = false
|
||||
c[:session_store] = 'cookie' # can also be 'memory', 'memcache', 'container', 'datamapper
|
||||
|
||||
# cookie session store configuration
|
||||
c[:session_secret_key] = 'bfa5ae857a67de5ef5bd123f3f0c41ffac540deb' # required for cookie session store
|
||||
c[:session_id_key] = '_web_session_id' # cookie session id key, defaults to "_session_id"
|
||||
end
|
||||
|
||||
Merb::BootLoader.before_app_loads do
|
||||
# This will get executed after dependencies have been loaded but before your app's classes have loaded.
|
||||
end
|
||||
|
||||
Merb::BootLoader.after_app_loads do
|
||||
# This will get executed after your app's classes have been loaded.
|
||||
end
|
11
web/config/rack.rb
Normal file
11
web/config/rack.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
# use PathPrefix Middleware if :path_prefix is set in Merb::Config
|
||||
if prefix = ::Merb::Config[:path_prefix]
|
||||
use Merb::Rack::PathPrefix, prefix
|
||||
end
|
||||
|
||||
# comment this out if you are running merb behind a load balancer
|
||||
# that serves static files
|
||||
use Merb::Rack::Static, Merb.dir_for(:public)
|
||||
|
||||
# this is our main merb application
|
||||
run Merb::Rack::Application.new
|
44
web/config/router.rb
Normal file
44
web/config/router.rb
Normal file
|
@ -0,0 +1,44 @@
|
|||
# Merb::Router is the request routing mapper for the merb framework.
|
||||
#
|
||||
# You can route a specific URL to a controller / action pair:
|
||||
#
|
||||
# match("/contact").
|
||||
# to(:controller => "info", :action => "contact")
|
||||
#
|
||||
# You can define placeholder parts of the url with the :symbol notation. These
|
||||
# placeholders will be available in the params hash of your controllers. For example:
|
||||
#
|
||||
# match("/books/:book_id/:action").
|
||||
# to(:controller => "books")
|
||||
#
|
||||
# Or, use placeholders in the "to" results for more complicated routing, e.g.:
|
||||
#
|
||||
# match("/admin/:module/:controller/:action/:id").
|
||||
# to(:controller => ":module/:controller")
|
||||
#
|
||||
# You can specify conditions on the placeholder by passing a hash as the second
|
||||
# argument of "match"
|
||||
#
|
||||
# match("/registration/:course_name", :course_name => /^[a-z]{3,5}-\d{5}$/).
|
||||
# to(:controller => "registration")
|
||||
#
|
||||
# You can also use regular expressions, deferred routes, and many other options.
|
||||
# See merb/specs/merb/router.rb for a fairly complete usage sample.
|
||||
|
||||
Merb.logger.info("Compiling routes...")
|
||||
Merb::Router.prepare do
|
||||
# RESTful routes
|
||||
# resources :posts
|
||||
|
||||
# Adds the required routes for merb-auth using the password slice
|
||||
slice(:merb_auth_slice_password, :name_prefix => nil, :path_prefix => "")
|
||||
|
||||
# This is the default route for /:controller/:action/:id
|
||||
# This is fine for most cases. If you're heavily using resource-based
|
||||
# routes, you may want to comment/remove this line to prevent
|
||||
# clients from calling your create or destroy actions with a GET
|
||||
default_routes
|
||||
|
||||
# Change this for your home page to be available at /
|
||||
# match('/').to(:controller => 'whatever', :action =>'index')
|
||||
end
|
1362
web/doc/rdoc/generators/merb_generator.rb
Normal file
1362
web/doc/rdoc/generators/merb_generator.rb
Normal file
File diff suppressed because it is too large
Load diff
640
web/doc/rdoc/generators/template/merb/api_grease.js
Normal file
640
web/doc/rdoc/generators/template/merb/api_grease.js
Normal file
|
@ -0,0 +1,640 @@
|
|||
|
||||
function setupPage(){
|
||||
hookUpActiveSearch();
|
||||
hookUpTabs();
|
||||
suppressPostbacks();
|
||||
var url_params = getUrlParams();
|
||||
if (url_params != null){
|
||||
loadUrlParams(url_params);
|
||||
}else{
|
||||
loadDefaults();
|
||||
}
|
||||
resizeDivs();
|
||||
window.onresize = function(){ resizeDivs(); };
|
||||
}
|
||||
|
||||
function getUrlParams(){
|
||||
var window_location = window.location.href
|
||||
var param_pos = window_location.search(/\?/)
|
||||
if (param_pos > 0){
|
||||
return(window_location.slice(param_pos, window_location.length));
|
||||
}else{
|
||||
return(null);
|
||||
}
|
||||
}
|
||||
|
||||
function loadUrlParams(url_param){
|
||||
//get the tabs
|
||||
var t = getTabs();
|
||||
// now find our variables
|
||||
var s_params = /(\?)(a=.+?)(&)(name=.*)/;
|
||||
var results = url_param.match(s_params);
|
||||
url_anchor = results[2].replace(/a=/,'');
|
||||
|
||||
if (url_anchor.match(/M.+/)){//load the methods tab and scroller content
|
||||
setActiveTabAndLoadContent(t[0]);
|
||||
}else{
|
||||
if(url_anchor.match(/C.+/)){ //load the classes tab and scroller content
|
||||
setActiveTabAndLoadContent(t[1]);
|
||||
}else{
|
||||
if (url_anchor.match(/F.+/)){//load the files tab
|
||||
setActiveTabAndLoadContent(t[2]);
|
||||
}else{
|
||||
// default to loading the methods
|
||||
setActiveTabAndLoadContent(t[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
paramLoadOfContentAnchor(url_anchor + "_link");
|
||||
}
|
||||
|
||||
function updateUrlParams(anchor_id, name){
|
||||
//Also setting the page title
|
||||
//window.document.title = name + " method - MerbBrain.com ";
|
||||
|
||||
//updating the window location
|
||||
var current_href = window.location.href;
|
||||
//var m_name = name.replace("?","?");
|
||||
var rep_str = ".html?a=" + anchor_id + "&name=" + name;
|
||||
var new_href = current_href.replace(/\.html.*/, rep_str);
|
||||
if (new_href != current_href){
|
||||
window.location.href = new_href;
|
||||
}
|
||||
}
|
||||
|
||||
//does as it says...
|
||||
function hookUpActiveSearch(){
|
||||
|
||||
var s_field = $('searchForm').getInputs('text')[0];
|
||||
//var s_field = document.forms[0].searchText;
|
||||
Event.observe(s_field, 'keydown', function(event) {
|
||||
var el = Event.element(event);
|
||||
var key = event.which || event.keyCode;
|
||||
|
||||
switch (key) {
|
||||
case Event.KEY_RETURN:
|
||||
forceLoadOfContentAnchor(getCurrentAnchor());
|
||||
Event.stop(event);
|
||||
break;
|
||||
|
||||
case Event.KEY_UP:
|
||||
scrollListToElementOffset(getCurrentAnchor(),-1);
|
||||
break;
|
||||
|
||||
case Event.KEY_DOWN:
|
||||
scrollListToElementOffset(getCurrentAnchor(),1);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Event.observe(s_field, 'keyup', function(event) {
|
||||
var el = Event.element(event);
|
||||
var key = event.which || event.keyCode;
|
||||
switch (key) {
|
||||
case Event.KEY_RETURN:
|
||||
Event.stop(event);
|
||||
break;
|
||||
|
||||
case Event.KEY_UP:
|
||||
break;
|
||||
|
||||
case Event.KEY_DOWN:
|
||||
break;
|
||||
|
||||
default:
|
||||
scrollToName(el.value);
|
||||
setSavedSearch(getCurrentTab(), el.value);
|
||||
break;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Event.observe(s_field, 'keypress', function(event){
|
||||
var el = Event.element(event);
|
||||
var key = event.which || event.keyCode;
|
||||
switch (key) {
|
||||
case Event.KEY_RETURN:
|
||||
Event.stop(event);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
//Event.observe(document, 'keypress', function(event){
|
||||
// var key = event.which || event.keyCode;
|
||||
// if (key == Event.KEY_TAB){
|
||||
// cycleNextTab();
|
||||
// Event.stop(event);
|
||||
// }
|
||||
//});
|
||||
}
|
||||
|
||||
function hookUpTabs(){
|
||||
|
||||
var tabs = getTabs();
|
||||
for(x=0; x < tabs.length; x++)
|
||||
{
|
||||
Event.observe(tabs[x], 'click', function(event){
|
||||
var el = Event.element(event);
|
||||
setActiveTabAndLoadContent(el);
|
||||
});
|
||||
//tabs[x].onclick = function (){ return setActiveTabAndLoadContent(this);}; //the prototype guys say this is bad..
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function suppressPostbacks(){
|
||||
Event.observe('searchForm', 'submit', function(event){
|
||||
Event.stop(event);
|
||||
});
|
||||
}
|
||||
|
||||
function loadDefaults(){
|
||||
var t = getTabs();
|
||||
setActiveTabAndLoadContent(t[0]); //default loading of the first tab
|
||||
}
|
||||
|
||||
function resizeDivs(){
|
||||
var inner_height = 700;
|
||||
if (window.innerHeight){
|
||||
inner_height = window.innerHeight; //all browsers except IE use this to determine the space available inside a window. Thank you Microsoft!!
|
||||
}else{
|
||||
if(document.documentElement.clientHeight > 0){ //IE uses this in 'strict' mode
|
||||
inner_height = document.documentElement.clientHeight;
|
||||
}else{
|
||||
inner_height = document.body.clientHeight; //IE uses this in 'quirks' mode
|
||||
}
|
||||
}
|
||||
$('rdocContent').style.height = (inner_height - 92) + "px";//Thankfully all browsers can agree on how to set the height of a div
|
||||
$('listScroller').style.height = (inner_height - 88) + "px";
|
||||
}
|
||||
|
||||
//The main function for handling clicks on the tabs
|
||||
function setActiveTabAndLoadContent(current_tab){
|
||||
changeLoadingStatus("on");
|
||||
var tab_string = String(current_tab.innerHTML).strip(); //thank you ProtoType!
|
||||
switch (tab_string){
|
||||
case "classes":
|
||||
setCurrentTab("classes");
|
||||
loadScrollerContent('fr_class_index.html');
|
||||
setSearchFieldValue(getSavedSearch("classes"));
|
||||
scrollToName(getSavedSearch("classes"));
|
||||
setSearchFocus();
|
||||
break;
|
||||
|
||||
case "files":
|
||||
setCurrentTab("files");
|
||||
loadScrollerContent('fr_file_index.html');
|
||||
setSearchFieldValue(getSavedSearch("files"));
|
||||
scrollToName(getSavedSearch("files"));
|
||||
setSearchFocus();
|
||||
break;
|
||||
|
||||
case "methods":
|
||||
setCurrentTab("methods");
|
||||
loadScrollerContent('fr_method_index.html');
|
||||
setSearchFieldValue(getSavedSearch("methods"));
|
||||
scrollToName(getSavedSearch("methods"));
|
||||
setSearchFocus();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
changeLoadingStatus("off");
|
||||
}
|
||||
|
||||
function cycleNextTab(){
|
||||
var currentT = getCurrentTab();
|
||||
var tabs = getTabs();
|
||||
if (currentT == "methods"){
|
||||
setActiveTabAndLoadContent(tabs[1]);
|
||||
setSearchFocus();
|
||||
}else{
|
||||
if (currentT == "classes"){
|
||||
setActiveTabAndLoadContent(tabs[2]);
|
||||
setSearchFocus();
|
||||
}else{
|
||||
if (currentT == "files"){
|
||||
setActiveTabAndLoadContent(tabs[0]);
|
||||
setSearchFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getTabs(){
|
||||
return($('groupType').getElementsByTagName('li'));
|
||||
}
|
||||
|
||||
var Active_Tab = "";
|
||||
function getCurrentTab(){
|
||||
return Active_Tab;
|
||||
}
|
||||
|
||||
function setCurrentTab(tab_name){
|
||||
var tabs = getTabs();
|
||||
for(x=0; x < tabs.length; x++)
|
||||
{
|
||||
if(tabs[x].innerHTML.strip() == tab_name) //W00t!!! String.prototype.strip!
|
||||
{
|
||||
tabs[x].className = "activeLi";
|
||||
Active_Tab = tab_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
tabs[x].className = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//These globals should not be used globally (hence the getters and setters)
|
||||
var File_Search = "";
|
||||
var Method_Search = "";
|
||||
var Class_Search = "";
|
||||
function setSavedSearch(tab_name, s_val){
|
||||
switch(tab_name){
|
||||
case "methods":
|
||||
Method_Search = s_val;
|
||||
break;
|
||||
case "files":
|
||||
File_Search = s_val;
|
||||
break;
|
||||
case "classes":
|
||||
Class_Search = s_val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function getSavedSearch(tab_name){
|
||||
switch(tab_name){
|
||||
case "methods":
|
||||
return (Method_Search);
|
||||
break;
|
||||
case "files":
|
||||
return (File_Search);
|
||||
break;
|
||||
case "classes":
|
||||
return (Class_Search);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//These globals handle the history stack
|
||||
|
||||
|
||||
function setListScrollerContent(s){
|
||||
|
||||
$('listScroller').innerHTML = s;
|
||||
}
|
||||
|
||||
function setMainContent(s){
|
||||
|
||||
$('rdocContent').innerHTML = s;
|
||||
}
|
||||
|
||||
function setSearchFieldValue(s){
|
||||
|
||||
document.forms[0].searchText.value = s;
|
||||
}
|
||||
|
||||
function getSearchFieldValue(){
|
||||
|
||||
return Form.Element.getValue('searchText');
|
||||
}
|
||||
|
||||
function setSearchFocus(){
|
||||
|
||||
document.forms[0].searchText.focus();
|
||||
}
|
||||
|
||||
var Anchor_ID_Of_Current = null; // holds the last highlighted anchor tag in the scroll lsit
|
||||
function getCurrentAnchor(){
|
||||
return(Anchor_ID_Of_Current);
|
||||
}
|
||||
|
||||
function setCurrentAnchor(a_id){
|
||||
Anchor_ID_Of_Current = a_id;
|
||||
}
|
||||
|
||||
//var Index_Of_Current = 0; //holds the last highlighted index
|
||||
//function getCurrentIndex(){
|
||||
// return (Index_Of_Current);
|
||||
//}
|
||||
|
||||
//function setCurrentIndex(new_i){
|
||||
// Index_Of_Current = new_i;
|
||||
//}
|
||||
|
||||
function loadScrollerContent(url){
|
||||
|
||||
var scrollerHtml = new Ajax.Request(url, {
|
||||
asynchronous: false,
|
||||
method: 'get',
|
||||
onComplete: function(method_data) {
|
||||
setListScrollerContent(method_data.responseText);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
//called primarily from the links inside the scroller list
|
||||
//loads the main page div then jumps to the anchor/element with id
|
||||
function loadContent(url, anchor_id){
|
||||
|
||||
var mainHtml = new Ajax.Request(url, {
|
||||
method: 'get',
|
||||
onLoading: changeLoadingStatus("on"),
|
||||
onSuccess: function(method_data) {
|
||||
setMainContent(method_data.responseText);},
|
||||
onComplete: function(request) {
|
||||
changeLoadingStatus("off");
|
||||
new jumpToAnchor(anchor_id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//An alternative function that also will stuff the index history for methods, files, classes
|
||||
function loadIndexContent(url, anchor_id, name, scope)
|
||||
{
|
||||
if (From_URL_Param == true){
|
||||
var mainHtml = new Ajax.Request(url, {
|
||||
method: 'get',
|
||||
onLoading: changeLoadingStatus("on"),
|
||||
onSuccess: function(method_data) {
|
||||
setMainContent(method_data.responseText);},
|
||||
onComplete: function(request) {
|
||||
changeLoadingStatus("off");
|
||||
updateBrowserBar(name, anchor_id, scope);
|
||||
new jumpToAnchor(anchor_id);}
|
||||
});
|
||||
From_URL_Param = false;
|
||||
}else{
|
||||
updateUrlParams(anchor_id, name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function updateBrowserBar(name, anchor_id, scope){
|
||||
if (getCurrentTab() == "methods"){
|
||||
$('browserBarInfo').update("<small>class/module:</small> <a href=\"#\" onclick=\"jumpToTop();\">" + scope + "</a> <small>method:</small> <strong><a href=\"#\" onclick=\"jumpToAnchor('"+ anchor_id +"')\">" + name + "</a></strong> ");
|
||||
}else{ if(getCurrentTab() == "classes"){
|
||||
$('browserBarInfo').update("<small>class/module:</small> <a href=\"#\" onclick=\"jumpToTop();\">" + scope + "::" + name + "</strong> ");
|
||||
}else{
|
||||
$('browserBarInfo').update("<small>file:</small> <a href=\"#\" onclick=\"jumpToTop();\">" + scope + "/" + name + "</strong> ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Force loads the contents of the index of the current scroller list. It does this by
|
||||
// pulling the onclick method out and executing it manually.
|
||||
function forceLoadOfContent(index_to_load){
|
||||
var scroller = $('listScroller');
|
||||
var a_array = scroller.getElementsByTagName('a');
|
||||
if ((index_to_load >= 0) && (index_to_load < a_array.length)){
|
||||
var load_element = a_array[index_to_load];
|
||||
var el_text = load_element.innerHTML.strip();
|
||||
setSearchFieldValue(el_text);
|
||||
setSavedSearch(getCurrentTab(), el_text);
|
||||
eval("new " + load_element.onclick);
|
||||
}
|
||||
}
|
||||
|
||||
function forceLoadOfContentAnchor(anchor_id){
|
||||
|
||||
var load_element = $(anchor_id);
|
||||
if (load_element != null){
|
||||
var el_text = load_element.innerHTML.strip();
|
||||
setSearchFieldValue(el_text);
|
||||
scrollToAnchor(anchor_id);
|
||||
setSavedSearch(getCurrentTab(), el_text);
|
||||
eval("new " + load_element.onclick);
|
||||
}
|
||||
}
|
||||
|
||||
var From_URL_Param = false;
|
||||
function paramLoadOfContentAnchor(anchor_id){
|
||||
From_URL_Param = true;
|
||||
forceLoadOfContentAnchor(anchor_id);
|
||||
}
|
||||
|
||||
//this handles the up/down keystrokes to move the selection of items in the list
|
||||
function scrollListToElementOffset(anchor_id, offset){
|
||||
var scroller = $('listScroller');
|
||||
var a_array = scroller.getElementsByTagName('a');
|
||||
var current_index = findIndexOfAnchor(a_array, anchor_id);
|
||||
if ((current_index >= 0) && (current_index < a_array.length)){
|
||||
scrollListToAnchor(a_array[current_index + offset].id);
|
||||
setListActiveAnchor(a_array[current_index + offset].id);
|
||||
}
|
||||
}
|
||||
|
||||
function findIndexOfAnchor(a_array, anchor_id){
|
||||
var found=false;
|
||||
var counter = 0;
|
||||
while(!found && counter < a_array.length){
|
||||
if (a_array[counter].id == anchor_id){
|
||||
found = true;
|
||||
}else{
|
||||
counter +=1;
|
||||
}
|
||||
}
|
||||
return(counter);
|
||||
}
|
||||
|
||||
function scrollToName(searcher_name){
|
||||
|
||||
var scroller = $('listScroller');
|
||||
var a_array = scroller.getElementsByTagName('a');
|
||||
|
||||
if (!searcher_name.match(new RegExp(/\s+/))){ //if searcher name is blank
|
||||
|
||||
var searcher_pattern = new RegExp("^"+searcher_name, "i"); //the "i" is for case INsensitive
|
||||
var found_index = -1;
|
||||
|
||||
var found = false;
|
||||
var x = 0;
|
||||
while(!found && x < a_array.length){
|
||||
if(a_array[x].innerHTML.match(searcher_pattern)){
|
||||
found = true;
|
||||
found_index = x;
|
||||
}
|
||||
else{
|
||||
x++;
|
||||
}
|
||||
}
|
||||
|
||||
// // an attempt at binary searching... have not given up on this yet...
|
||||
//found_index = binSearcher(searcher_pattern, a_array, 0, a_array.length);
|
||||
|
||||
if ((found_index >= 0) && (found_index < a_array.length)){
|
||||
|
||||
scrollListToAnchor(a_array[found_index].id);//scroll to the item
|
||||
setListActiveAnchor(a_array[found_index].id);//highlight the item
|
||||
}
|
||||
}else{ //since searcher name is blank
|
||||
//scrollListToIndex(a_array, 0);//scroll to the item
|
||||
//setListActiveItem(a_array, 0);//highlight the item
|
||||
}
|
||||
}
|
||||
|
||||
function scrollToAnchor(anchor_id){
|
||||
var scroller = $('listScroller');
|
||||
if ($(anchor_id) != null){
|
||||
scrollListToAnchor(anchor_id);
|
||||
setListActiveAnchor(anchor_id);
|
||||
}
|
||||
}
|
||||
|
||||
function getY(element){
|
||||
|
||||
var y = 0;
|
||||
for( var e = element; e; e = e.offsetParent)//iterate the offset Parents
|
||||
{
|
||||
y += e.offsetTop; //add up the offsetTop values
|
||||
}
|
||||
//for( e = element.parentNode; e && e != document.body; e = e.parentNode)
|
||||
// if (e.scrollTop) y -= e.scrollTop; //subtract scrollbar values
|
||||
return y;
|
||||
}
|
||||
|
||||
//function setListActiveItem(item_array, active_index){
|
||||
//
|
||||
// item_array[getCurrentIndex()].className = "";
|
||||
// setCurrentIndex(active_index);
|
||||
// item_array[getCurrentIndex()].className = "activeA"; //setting the active class name
|
||||
//}
|
||||
|
||||
function setListActiveAnchor(active_anchor){
|
||||
if ((getCurrentAnchor() != null) && ($(getCurrentAnchor()) != null)){
|
||||
$(getCurrentAnchor()).className = "";
|
||||
}
|
||||
setCurrentAnchor(active_anchor);
|
||||
$(getCurrentAnchor()).className = "activeA";
|
||||
|
||||
}
|
||||
|
||||
//handles the scrolling of the list and setting of the current index
|
||||
//function scrollListToIndex(a_array, scroll_index){
|
||||
// if (scroll_index > 0){
|
||||
// var scroller = $('listScroller');
|
||||
// scroller.scrollTop = getY(a_array[scroll_index]) - 120; //the -120 is what keeps it from going to the top...
|
||||
// }
|
||||
//}
|
||||
|
||||
function scrollListToAnchor(scroll2_anchor){
|
||||
var scroller = $('listScroller');
|
||||
scroller.scrollTop = getY($(scroll2_anchor)) - 120;
|
||||
}
|
||||
|
||||
function jumpToAnchor(anchor_id){
|
||||
|
||||
var contentScroller = $('rdocContent');
|
||||
var a_div = $(anchor_id);
|
||||
contentScroller.scrollTop = getY(a_div) - 80; //80 is the offset to adjust scroll point
|
||||
var a_title = $(anchor_id + "_title");
|
||||
a_title.style.backgroundColor = "#222";
|
||||
a_title.style.color = "#FFF";
|
||||
a_title.style.padding = "3px";
|
||||
// a_title.style.borderBottom = "2px solid #ccc";
|
||||
|
||||
//other attempts
|
||||
//a_div.className = "activeMethod"; //setting the active class name
|
||||
//a_div.style.backgroundColor = "#ffc";
|
||||
//var titles = a_div.getElementsByClassName("title");
|
||||
//titles[0].className = "activeTitle";
|
||||
|
||||
}
|
||||
|
||||
function jumpToTop(){
|
||||
$('rdocContent').scrollTop = 0;
|
||||
}
|
||||
|
||||
function changeLoadingStatus(status){
|
||||
if (status == "on"){
|
||||
$('loadingStatus').show();
|
||||
}
|
||||
else{
|
||||
$('loadingStatus').hide();
|
||||
}
|
||||
}
|
||||
|
||||
//************* Misc functions (mostly from the old rdocs) ***********************
|
||||
//snagged code from the old templating system
|
||||
function toggleSource( id ){
|
||||
|
||||
var elem
|
||||
var link
|
||||
|
||||
if( document.getElementById )
|
||||
{
|
||||
elem = document.getElementById( id )
|
||||
link = document.getElementById( "l_" + id )
|
||||
}
|
||||
else if ( document.all )
|
||||
{
|
||||
elem = eval( "document.all." + id )
|
||||
link = eval( "document.all.l_" + id )
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
if( elem.style.display == "block" )
|
||||
{
|
||||
elem.style.display = "none"
|
||||
link.innerHTML = "show source"
|
||||
}
|
||||
else
|
||||
{
|
||||
elem.style.display = "block"
|
||||
link.innerHTML = "hide source"
|
||||
}
|
||||
}
|
||||
|
||||
function openCode( url ){
|
||||
window.open( url, "SOURCE_CODE", "width=400,height=400,scrollbars=yes" )
|
||||
}
|
||||
|
||||
//this function handles the ajax calling and afterits loaded the jumping to the anchor...
|
||||
function jsHref(url){
|
||||
//alert(url);
|
||||
var mainHtml = new Ajax.Request(url, {
|
||||
method: 'get',
|
||||
onSuccess: function(method_data) {
|
||||
setMainContent(method_data.responseText);}
|
||||
});
|
||||
}
|
||||
|
||||
//function comparePatterns(string, regexp){
|
||||
// var direction = 0;
|
||||
//
|
||||
//
|
||||
// return (direction)
|
||||
//}
|
||||
|
||||
////returns the index of the element
|
||||
//function binSearcher(regexp_pattern, list, start_index, stop_index){
|
||||
// //divide the list in half
|
||||
// var split_point = 0;
|
||||
// split_point = parseInt((stop_index - start_index)/2);
|
||||
// direction = comparePatterns(list[split_point].innerHTML, regexp_pattern);
|
||||
// if(direction < 0)
|
||||
// return (binSearcher(regexp_pattern, list, start_index, split_point));
|
||||
// else
|
||||
// if(direction > 0)
|
||||
// return (binSearcher(regexp_pattern, list, split_point, stop_index));
|
||||
// else
|
||||
// return(split_point);
|
||||
//
|
||||
//}
|
||||
|
||||
|
||||
|
37
web/doc/rdoc/generators/template/merb/index.html.erb
Normal file
37
web/doc/rdoc/generators/template/merb/index.html.erb
Normal file
|
@ -0,0 +1,37 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html lang='en' xml:lang='en' xmlns='http://www.w3.org/1999/xhtml'>
|
||||
<head>
|
||||
<title>Documentation</title>
|
||||
<meta content='text/html;charset=UTF-8' http-equiv='content-type' />
|
||||
<meta content='all' name='robots' />
|
||||
<meta content='text/html;charset=utf-8' http-equiv='content-type' />
|
||||
<meta content='no' http-equiv='msthemecompatible' />
|
||||
<meta content='false' http-equiv='imagetoolbar' />
|
||||
<link href="generators/template/merb/merb.css" media="screen" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id='content'>
|
||||
<div class='wrap_to_center'>
|
||||
<div class='full_width' id='content_top'>
|
||||
<div id='content_bottom'>
|
||||
<div id='content_full'>
|
||||
<h1>Documentation</h1>
|
||||
<ul>
|
||||
<% @directories.each do |directory| %>
|
||||
<li id="merb-core"><a href="<%= directory %>/index.html"><%= directory.capitalize %></a></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id='footer'>
|
||||
<div class='wrap_to_center'>
|
||||
<p>
|
||||
© 2008, Merb Team | Merb is released under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT License</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
252
web/doc/rdoc/generators/template/merb/merb.css
Normal file
252
web/doc/rdoc/generators/template/merb/merb.css
Normal file
|
@ -0,0 +1,252 @@
|
|||
html, body, div, span, applet, object, iframe,h1, h2, h3, h4, h5, h6, p, blockquote, pre,a, abbr, acronym, address, big, cite, code,del, dfn, em, font, img, ins, kbd, q, s, samp,small, strike, strong, sub, sup, tt, var,dl, dt, dd, ol, ul, li,fieldset, form, label, legend,table, caption, tbody, tfoot, thead, tr, th, td {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font-weight: inherit;
|
||||
font-style: inherit;
|
||||
font-size: 100%;
|
||||
font-family: inherit;
|
||||
vertical-align: baseline; }
|
||||
|
||||
/* GENERAL RULES */
|
||||
|
||||
body {
|
||||
background: #000 url(../img/body.gif) repeat-x bottom center;
|
||||
color: #000;
|
||||
font: normal 12px "Lucida Grande", "Arial", sans-serif;
|
||||
line-height: 1;
|
||||
}
|
||||
ul {list-style-type: none;}
|
||||
#content_full ul.revisions{list-style-type: disc;}
|
||||
#content_full ul.revisions li{margin-left: 15px;padding: 3px 0;}
|
||||
li a {display: block;}
|
||||
#content_full ul.revisions li a{display: inline;}
|
||||
strong {font-weight: bold;}
|
||||
table {border-collapse: separate;border-spacing: 0; }
|
||||
caption, th, td {text-align: left;font-weight: normal; }
|
||||
.invisible {display: none;}
|
||||
.full_width {width:100%;}
|
||||
|
||||
/* LAYOUT */
|
||||
|
||||
.wrap_to_center, #foot {
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
width: 800px;
|
||||
}
|
||||
|
||||
#content {width: 100%;}
|
||||
|
||||
#content_top {
|
||||
background: #fff url(../img/content_top.gif) no-repeat top center;
|
||||
float:left;
|
||||
margin:25px 0px;
|
||||
width:100%;
|
||||
}
|
||||
#content_bottom {
|
||||
background: url(../img/content_bottom.gif) no-repeat bottom center;
|
||||
width:100%;
|
||||
float:left;
|
||||
}
|
||||
#content_main {
|
||||
float:left;
|
||||
margin: 10px 20px 20px 20px;
|
||||
width:506px;
|
||||
}
|
||||
#content p {
|
||||
line-height:17px;
|
||||
}
|
||||
#content_full {margin: 10px 20px 20px 20px;}
|
||||
|
||||
/* HEADER & NAVIGATION */
|
||||
|
||||
#header {
|
||||
background: #1db900 url(../img/header_waves.gif) repeat-x top center;
|
||||
height:74px;
|
||||
width: 100%;
|
||||
}
|
||||
#waves {
|
||||
background: url(../img/header_waves.gif)no-repeat top left;
|
||||
height:74px;
|
||||
width:980px;
|
||||
}
|
||||
#header img {margin-top:8px; float:left;}
|
||||
#header a {color:#fff; text-decoration:none;}
|
||||
#header a:hover {color:#000;}
|
||||
ul#nav {float:right;display:block;width:43.3em;margin-top:25px;}
|
||||
ul#nav li {display:block;float:left;}
|
||||
ul#nav li a {display:block;float:left;margin:0px 5px;padding:6px 9px 31px 9px;}
|
||||
ul#nav li a:hover {background:url(../img/header_hover.gif) repeat-x bottom center;}
|
||||
ul#nav li a#active {background:url(../img/header_arrow.gif)no-repeat bottom center;}
|
||||
ul#nav li.last a {margin-right:0;}
|
||||
|
||||
/* TEXT FORMATTING */
|
||||
|
||||
h1 {
|
||||
border-bottom:2px solid #ccc;
|
||||
color:#000;
|
||||
font:bold 28px "Arial" sans-serif;
|
||||
letter-spacing:1px;
|
||||
margin:20px 0px;
|
||||
text-align:left;
|
||||
width:100%;
|
||||
}
|
||||
h1.home {
|
||||
border:0;
|
||||
color:#fff;
|
||||
font-size:36px;
|
||||
margin:20px 0px;
|
||||
text-align:center;
|
||||
}
|
||||
h2 {
|
||||
color:#7aad00;
|
||||
font:bold 22px "Lucida Grande" sans-serif;
|
||||
margin:10px 0px;
|
||||
}
|
||||
h3 {
|
||||
font:bold 16px "Lucida Grande";
|
||||
margin:10px 0px;
|
||||
}
|
||||
#content a {color:#d7ff00;}
|
||||
#content a:hover {background:#d7ff00;color:#000;}
|
||||
#content_main ul {margin:10px 0px;}
|
||||
#content_main ul li {
|
||||
background: url(../img/li.gif) no-repeat left center;
|
||||
padding: 4px 4px 4px 16px;
|
||||
font-weight:bold;
|
||||
}
|
||||
p {margin-bottom:12px;}
|
||||
#content_main a,#content_full a {color:#11b716;font-weight:bold;}
|
||||
#content_main a:hover,#content_full a:hover {background:#22d716;}
|
||||
pre {
|
||||
background:#222;
|
||||
color:#fff;
|
||||
font:12px "Courier" serif;
|
||||
line-height:18px;
|
||||
padding: 12px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
code {
|
||||
font:bold 12px "Courier" serif;
|
||||
}
|
||||
pre code {font-weight:normal;}
|
||||
|
||||
/* SIDEBAR FOR CONTENT */
|
||||
|
||||
#content_sidebar {
|
||||
float: left;
|
||||
margin: 20px 20px 15px 10px;
|
||||
width: 224px;
|
||||
}
|
||||
.sidebar_top {
|
||||
background:#868686 url(../img/sidebar_top.gif) no-repeat top center;
|
||||
margin-bottom:12px;
|
||||
width:224px;
|
||||
}
|
||||
dl.sidebar_bottom {
|
||||
background: url(../img/sidebar_bottom.gif) no-repeat bottom center;
|
||||
padding:12px;
|
||||
}
|
||||
dl.sidebar_bottom dt {
|
||||
color:#fff;
|
||||
font:bold 14px "Lucida Grande" sans-serif;
|
||||
margin-bottom:6px;
|
||||
}
|
||||
dl.sidebar_bottom dd {padding:3px 0px;}
|
||||
#content_sidebar p {padding:10px 0px;}
|
||||
p#rss a {
|
||||
background: url(../img/rss.gif) no-repeat left center;
|
||||
color:#000;
|
||||
font:bold 14px "Lucida Grande";
|
||||
padding: 8px 6px 8px 34px;
|
||||
text-decoration:none;
|
||||
}
|
||||
p#rss a:hover {
|
||||
background: url(../img/rss.gif) no-repeat left center;
|
||||
background-color:#fff;
|
||||
text-decoration:underline;
|
||||
}
|
||||
|
||||
/* FOOTER */
|
||||
|
||||
#footer {background:#444; clear:both;}
|
||||
#footer p {padding:12px; color:#999; margin:0; text-align:center;}
|
||||
|
||||
/* FEATURES PAGE */
|
||||
.feature {
|
||||
background-repeat:no-repeat;
|
||||
background-position:top left;
|
||||
border-bottom:2px solid #ccc;
|
||||
padding-left:150px;
|
||||
}
|
||||
div#speed {background-image: url(../img/feature_speed.gif);}
|
||||
div#light {background-image: url(../img/feature_light.gif);}
|
||||
div#power {background-image: url(../img/feature_power.gif);}
|
||||
|
||||
.quicklinks_top {
|
||||
background:#868686 url(../img/quicklinks_top.gif) no-repeat top center;
|
||||
float:right;
|
||||
margin-bottom:12px;
|
||||
width:169px;
|
||||
}
|
||||
ul.quicklinks_bottom {
|
||||
background: url(../img/quicklinks_bottom.gif) no-repeat bottom center;
|
||||
padding:12px;
|
||||
}
|
||||
ul.quicklinks_bottom li {
|
||||
display:block;
|
||||
padding:3px 0px;
|
||||
}
|
||||
#content_full ul.quicklinks_bottom li a{
|
||||
color:#d7ff00;
|
||||
display:inline;
|
||||
}
|
||||
#content_full ul.quicklinks_bottom li a:hover {
|
||||
background:#d7ff00;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
/* DOCUMENTATION PAGE */
|
||||
.sub-framework {
|
||||
border-bottom:2px solid #ccc;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
|
||||
/* ICONS FOR HOMEPAGE */
|
||||
|
||||
#icons_top {
|
||||
background: url(../img/icons_top.gif) no-repeat top center;
|
||||
float:left;
|
||||
width:800px;
|
||||
}
|
||||
#icons_bottom {
|
||||
background: url(../img/icons_bottom.gif) no-repeat bottom center;
|
||||
float:left;
|
||||
width:800px;
|
||||
}
|
||||
#icons_top dl {
|
||||
color:#fff;
|
||||
float:left;
|
||||
width: 224px;
|
||||
padding: 15px 20px;
|
||||
}
|
||||
#icons_top dt {
|
||||
background-repeat:no-repeat;
|
||||
background-position:center 2.5em;
|
||||
color:#35d726;
|
||||
font:bold 18px 'Lucida Grande' sans-serif;
|
||||
padding: 6px 6px 150px 6px;
|
||||
text-align:center;
|
||||
}
|
||||
#icons_top dd {
|
||||
font: 11px "Lucida Grande";
|
||||
line-height:18px;
|
||||
text-align:center;
|
||||
}
|
||||
dl#speed, dl#light {border-right:1px solid #444;}
|
||||
dl#light, dl#power {border-left:1px solid #000;}
|
||||
dl#speed dt {background-image: url(../img/icon_speed.gif);}
|
||||
dl#light dt {background-image: url(../img/icon_light.gif);}
|
||||
dl#power dt {background-image: url(../img/icon_power.gif);}
|
351
web/doc/rdoc/generators/template/merb/merb.rb
Normal file
351
web/doc/rdoc/generators/template/merb/merb.rb
Normal file
|
@ -0,0 +1,351 @@
|
|||
module RDoc
|
||||
module Page
|
||||
|
||||
STYLE = File.read(File.join(File.dirname(__FILE__), 'merb_doc_styles.css'))
|
||||
FONTS = ""
|
||||
|
||||
###################################################################
|
||||
|
||||
CLASS_PAGE = <<HTML
|
||||
<div id="%class_seq%">
|
||||
<div class='banner'>
|
||||
<span class="file-title-prefix">%classmod%</span><br />%full_name%<br/>
|
||||
In:
|
||||
START:infiles
|
||||
<a href="#" onclick="jsHref('%full_path_url%');">%full_path%</a>
|
||||
IF:cvsurl
|
||||
(<a href="#" onclick="jsHref('%cvsurl%');">CVS</a>)
|
||||
ENDIF:cvsurl
|
||||
END:infiles
|
||||
|
||||
IF:parent
|
||||
Parent:
|
||||
IF:par_url
|
||||
<a href="#" onclick="jsHref('%par_url%');">
|
||||
ENDIF:par_url
|
||||
%parent%
|
||||
IF:par_url
|
||||
</a>
|
||||
ENDIF:par_url
|
||||
ENDIF:parent
|
||||
</div>
|
||||
HTML
|
||||
|
||||
###################################################################
|
||||
|
||||
METHOD_LIST = <<HTML
|
||||
<div id="content">
|
||||
IF:diagram
|
||||
<table cellpadding='0' cellspacing='0' border='0' width="100%"><tr><td align="center">
|
||||
%diagram%
|
||||
</td></tr></table>
|
||||
ENDIF:diagram
|
||||
|
||||
IF:description
|
||||
<div class="description">%description%</div>
|
||||
ENDIF:description
|
||||
|
||||
IF:requires
|
||||
<div class="sectiontitle">Required Files</div>
|
||||
<ul>
|
||||
START:requires
|
||||
<li><a href="#" onclick="jsHref('%href%');">%name%</a></li>
|
||||
END:requires
|
||||
</ul>
|
||||
ENDIF:requires
|
||||
|
||||
IF:toc
|
||||
<div class="sectiontitle">Contents</div>
|
||||
<ul>
|
||||
START:toc
|
||||
<li><a href="#" onclick="jsHref('%href%');">%secname%</a></li>
|
||||
END:toc
|
||||
</ul>
|
||||
ENDIF:toc
|
||||
|
||||
IF:methods
|
||||
<div class="sectiontitle">Methods</div>
|
||||
<ul>
|
||||
START:methods
|
||||
<li><a href="index.html?a=%href%&name=%name%" >%name%</a></li>
|
||||
END:methods
|
||||
</ul>
|
||||
ENDIF:methods
|
||||
|
||||
IF:includes
|
||||
<div class="sectiontitle">Included Modules</div>
|
||||
<ul>
|
||||
START:includes
|
||||
<li><a href="#" onclick="jsHref('%href%');">%name%</a></li>
|
||||
END:includes
|
||||
</ul>
|
||||
ENDIF:includes
|
||||
|
||||
START:sections
|
||||
IF:sectitle
|
||||
<div class="sectiontitle"><a href="%secsequence%">%sectitle%</a></div>
|
||||
IF:seccomment
|
||||
<div class="description">
|
||||
%seccomment%
|
||||
</div>
|
||||
ENDIF:seccomment
|
||||
ENDIF:sectitle
|
||||
|
||||
IF:classlist
|
||||
<div class="sectiontitle">Classes and Modules</div>
|
||||
%classlist%
|
||||
ENDIF:classlist
|
||||
|
||||
IF:constants
|
||||
<div class="sectiontitle">Constants</div>
|
||||
<table border='0' cellpadding='5'>
|
||||
START:constants
|
||||
<tr valign='top'>
|
||||
<td class="attr-name">%name%</td>
|
||||
<td>=</td>
|
||||
<td class="attr-value">%value%</td>
|
||||
</tr>
|
||||
IF:desc
|
||||
<tr valign='top'>
|
||||
<td> </td>
|
||||
<td colspan="2" class="attr-desc">%desc%</td>
|
||||
</tr>
|
||||
ENDIF:desc
|
||||
END:constants
|
||||
</table>
|
||||
ENDIF:constants
|
||||
|
||||
IF:attributes
|
||||
<div class="sectiontitle">Attributes</div>
|
||||
<table border='0' cellpadding='5'>
|
||||
START:attributes
|
||||
<tr valign='top'>
|
||||
<td class='attr-rw'>
|
||||
IF:rw
|
||||
[%rw%]
|
||||
ENDIF:rw
|
||||
</td>
|
||||
<td class='attr-name'>%name%</td>
|
||||
<td class='attr-desc'>%a_desc%</td>
|
||||
</tr>
|
||||
END:attributes
|
||||
</table>
|
||||
ENDIF:attributes
|
||||
|
||||
IF:method_list
|
||||
START:method_list
|
||||
IF:methods
|
||||
<div class="sectiontitle">%type% %category% methods</div>
|
||||
START:methods
|
||||
<div id="%m_seq%" class="method">
|
||||
<div id="%m_seq%_title" class="title">
|
||||
IF:callseq
|
||||
<b>%callseq%</b>
|
||||
ENDIF:callseq
|
||||
IFNOT:callseq
|
||||
<b>%name%</b>%params%
|
||||
ENDIF:callseq
|
||||
IF:codeurl
|
||||
[ <a href="javascript:openCode('%codeurl%')">source</a> ]
|
||||
ENDIF:codeurl
|
||||
</div>
|
||||
IF:m_desc
|
||||
<div class="description">
|
||||
%m_desc%
|
||||
</div>
|
||||
ENDIF:m_desc
|
||||
IF:aka
|
||||
<div class="aka">
|
||||
This method is also aliased as
|
||||
START:aka
|
||||
<a href="index.html?a=%aref%&name=%name%">%name%</a>
|
||||
END:aka
|
||||
</div>
|
||||
ENDIF:aka
|
||||
IF:sourcecode
|
||||
<div class="sourcecode">
|
||||
<p class="source-link">[ <a href="javascript:toggleSource('%aref%_source')" id="l_%aref%_source">show source</a> ]</p>
|
||||
<div id="%aref%_source" class="dyn-source">
|
||||
<pre>
|
||||
%sourcecode%
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
ENDIF:sourcecode
|
||||
</div>
|
||||
END:methods
|
||||
ENDIF:methods
|
||||
END:method_list
|
||||
ENDIF:method_list
|
||||
END:sections
|
||||
</div>
|
||||
HTML
|
||||
|
||||
|
||||
|
||||
|
||||
BODY = <<ENDBODY
|
||||
!INCLUDE! <!-- banner header -->
|
||||
|
||||
<div id="bodyContent" >
|
||||
#{METHOD_LIST}
|
||||
</div>
|
||||
|
||||
ENDBODY
|
||||
|
||||
|
||||
|
||||
SRC_BODY = <<ENDSRCBODY
|
||||
!INCLUDE! <!-- banner header -->
|
||||
|
||||
<div id="bodyContent" >
|
||||
<h2>Source Code</h2>
|
||||
<pre>%file_source_code%</pre>
|
||||
</div>
|
||||
ENDSRCBODY
|
||||
|
||||
|
||||
###################### File Page ##########################
|
||||
FILE_PAGE = <<HTML
|
||||
<div id="fileHeader">
|
||||
<h1>%short_name%</h1>
|
||||
<table class="header-table">
|
||||
<tr class="top-aligned-row">
|
||||
<td><strong>Path:</strong></td>
|
||||
<td>%full_path%
|
||||
IF:cvsurl
|
||||
(<a href="%cvsurl%"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
|
||||
ENDIF:cvsurl
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="top-aligned-row">
|
||||
<td><strong>Last Update:</strong></td>
|
||||
<td>%dtm_modified%</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
HTML
|
||||
|
||||
|
||||
#### This is not used but kept for historical purposes
|
||||
########################## Source code ##########################
|
||||
# Separate page onlye
|
||||
|
||||
SRC_PAGE = <<HTML
|
||||
<html>
|
||||
<head><title>%title%</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=%charset%">
|
||||
<style>
|
||||
.ruby-comment { color: green; font-style: italic }
|
||||
.ruby-constant { color: #4433aa; font-weight: bold; }
|
||||
.ruby-identifier { color: #222222; }
|
||||
.ruby-ivar { color: #2233dd; }
|
||||
.ruby-keyword { color: #3333FF; font-weight: bold }
|
||||
.ruby-node { color: #777777; }
|
||||
.ruby-operator { color: #111111; }
|
||||
.ruby-regexp { color: #662222; }
|
||||
.ruby-value { color: #662222; font-style: italic }
|
||||
.kw { color: #3333FF; font-weight: bold }
|
||||
.cmt { color: green; font-style: italic }
|
||||
.str { color: #662222; font-style: italic }
|
||||
.re { color: #662222; }
|
||||
</style>
|
||||
</head>
|
||||
<body bgcolor="white">
|
||||
<pre>%code%</pre>
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
########################### source page body ###################
|
||||
|
||||
SCR_CODE_BODY = <<HTML
|
||||
<div id="source">
|
||||
%source_code%
|
||||
</div>
|
||||
|
||||
HTML
|
||||
|
||||
########################## Index ################################
|
||||
|
||||
FR_INDEX_BODY = <<HTML
|
||||
!INCLUDE!
|
||||
HTML
|
||||
|
||||
FILE_INDEX = <<HTML
|
||||
<ul>
|
||||
START:entries
|
||||
<li><a id="%seq_id%_link" href="index.html?a=%seq_id%&name=%name%" onclick="loadIndexContent('%href%','%seq_id%','%name%', '%scope%');">%name%</a><small>%scope%</small></li>
|
||||
END:entries
|
||||
</ul>
|
||||
HTML
|
||||
|
||||
CLASS_INDEX = FILE_INDEX
|
||||
METHOD_INDEX = FILE_INDEX
|
||||
|
||||
INDEX = <<HTML
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<meta name="description" content="A nifty way to interact with the Merb API" />
|
||||
<meta name="author" content="created by Brian Chamberlain. You can contact me using 'blchamberlain' on the gmail." />
|
||||
<meta name="keywords" content="merb, ruby, purple, monkey, dishwasher" />
|
||||
<title>Merb | %title% API Documentation</title>
|
||||
<link rel="stylesheet" href="http://merbivore.com/documentation/stylesheet.css" type="text/css" media="screen" />
|
||||
<script type="text/javascript" src="http://merbivore.com/documentation/prototype.js" ></script>
|
||||
<script type="text/javascript" src="http://merbivore.com/documentation/api_grease.js" ></script>
|
||||
</head>
|
||||
<body onload="setupPage();">
|
||||
<ul id="groupType">
|
||||
<li>methods</li>
|
||||
<li>classes</li>
|
||||
<li>files</li>
|
||||
<li id="loadingStatus" style="display:none;"> loading...</li>
|
||||
</ul>
|
||||
<div id="listFrame">
|
||||
<div id="listSearch">
|
||||
<form id="searchForm" method="get" action="#" onsubmit="return false">
|
||||
<input type="text" name="searchText" id="searchTextField" size="30" autocomplete="off" />
|
||||
</form>
|
||||
</div>
|
||||
<div id="listScroller">
|
||||
Loading via ajax... this could take a sec.
|
||||
</div>
|
||||
</div>
|
||||
<div id="browserBar">
|
||||
<span id="browserBarInfo">%title% README</span>
|
||||
</div>
|
||||
<div id="rdocContent">
|
||||
%content%
|
||||
</div>
|
||||
<div id="floater">
|
||||
<strong>Documentation for %title% </strong><a href="#" onmouseover="$('tips').show();" onmouseout="$('tips').hide();">usage tips</a>
|
||||
<div id="tips" style="position:absolute;width:350px;top:15px;right:20px;padding:5px;border:1px solid #333;background-color:#fafafa;display:none;">
|
||||
<p><strong>Some tips</strong>
|
||||
<ul>
|
||||
<li> Up/Down keys move through the search list</li>
|
||||
<li> Return/enter key loads selected item</li>
|
||||
<li> Want to use this RDOC template for your own project? Check out <br /> http://rubyforge.org/projects/jaxdoc</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
<div id="blowOutListBox" style="display:none;"> </div>
|
||||
<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
_uacct = "UA-3085184-1";
|
||||
urchinTracker();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
API_GREASE_JS = File.read(File.join(File.dirname(__FILE__), 'api_grease.js'))
|
||||
|
||||
PROTOTYPE_JS = File.read(File.join(File.dirname(__FILE__), 'prototype.js'))
|
||||
end
|
||||
end
|
||||
|
492
web/doc/rdoc/generators/template/merb/merb_doc_styles.css
Normal file
492
web/doc/rdoc/generators/template/merb/merb_doc_styles.css
Normal file
|
@ -0,0 +1,492 @@
|
|||
html, body {
|
||||
padding:10px 0px 0px 5px;
|
||||
margin: 0px;
|
||||
font-family: "Lucida Grande", "Lucida Sans Unicode", sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
body {
|
||||
background: #000000 url(http://merbivore.com/img/header_waves.gif) repeat-x scroll center top;
|
||||
}
|
||||
|
||||
td, p {
|
||||
background: #FFF;
|
||||
color: #000;
|
||||
margin: 0px;
|
||||
font-size: small;
|
||||
line-height: 17px;
|
||||
margin-bottom 12px;
|
||||
}
|
||||
|
||||
#floater {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
#floater strong {
|
||||
color: white;
|
||||
}
|
||||
|
||||
#floater a {
|
||||
color: black;
|
||||
}
|
||||
|
||||
#floater a:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
|
||||
/*holds the whole searching/drill down stuff */
|
||||
#listFrame{
|
||||
float:left;
|
||||
padding: 2px;
|
||||
width: 350px;
|
||||
background-color: #868686;
|
||||
border: 1px solid #999;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
#browserBar{
|
||||
height: 25px;
|
||||
padding:11px 0px 0px 0px;
|
||||
margin:0px;
|
||||
background-color: #868686;
|
||||
border-top: 1px solid #999;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#browserBar a{
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.button{
|
||||
text-decoration: none;
|
||||
padding:3px 8px 3px 8px;
|
||||
border: 1px solid #66a;
|
||||
background-color: #ccf;
|
||||
color: #66a;
|
||||
}
|
||||
|
||||
.buttonInactive{
|
||||
text-decoration: none;
|
||||
padding:3px 8px 3px 8px;
|
||||
border: 1px solid #999;
|
||||
background-color: #ccc;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.miniButton{
|
||||
text-decoration: none;
|
||||
padding:3px 2px 3px 2px;
|
||||
border: 1px solid #66a;
|
||||
background-color: #ccf;
|
||||
color: #66a;
|
||||
}
|
||||
|
||||
.miniButtonInactive{
|
||||
text-decoration: none;
|
||||
padding:3px 2px 3px 2px;
|
||||
border: 1px solid #999;
|
||||
background-color: #ccc;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
#blowOutListBox{
|
||||
position: absolute;
|
||||
top: 63px;
|
||||
left: 399px;
|
||||
border: 1px solid #999;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
z-index: 1000;
|
||||
background-color: #ccf;
|
||||
color: #66a;
|
||||
}
|
||||
|
||||
#blowOutListBox ul{
|
||||
list-style-type:none;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
#blowOutListBox ul li{
|
||||
padding: 3px;
|
||||
margin: 0px;
|
||||
line-height: 1.1em;
|
||||
|
||||
}
|
||||
|
||||
#blowOutListBox ul li a{
|
||||
text-decoration: none;
|
||||
padding: 3px;
|
||||
}
|
||||
#blowOutListBox ul li a:hover{
|
||||
background-color: #ddf;
|
||||
}
|
||||
|
||||
/*holds the content for browsing etc... also is the target of method/class/file name clicks */
|
||||
#rdocContent{
|
||||
height: 600px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #999;
|
||||
border-left: 0px;
|
||||
padding:5px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/*the grouping for methods,files,class,all... i.e. the tabs */
|
||||
ul#groupType{
|
||||
list-style-type: none;
|
||||
padding: 0px;
|
||||
padding-left: 5px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
ul#groupType li{
|
||||
color: white;
|
||||
display:inline;
|
||||
padding: 5px 5px 0px 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
ul#groupType li#loadingStatus{
|
||||
margin: 3px;
|
||||
border: 0px;
|
||||
padding: 3px 3px 6px 3px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
ul#groupType li.activeLi{
|
||||
border: 1px solid #999;
|
||||
border-bottom: 0px;
|
||||
background-color: #868686;
|
||||
font-weight: bold;
|
||||
padding-bottom: 1px;
|
||||
}
|
||||
|
||||
#listSearch{
|
||||
height: 25px;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
#listSearch input[type=text]{
|
||||
width: 340px;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
#listScroller{
|
||||
width: 342px;
|
||||
height: 700px;
|
||||
margin: 3px;
|
||||
background-color: #fcfcfc;
|
||||
border: 1px solid #999;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#listScroller ul{
|
||||
width: 500px;
|
||||
padding:0px;
|
||||
margin:0px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
#listScroller li{
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
display: block;
|
||||
line-height: 1.1em;
|
||||
}
|
||||
|
||||
a, h1 a, h2 a, .sectiontitle a, #listScroller a{
|
||||
color: #11B716;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
padding: 0px 1px 1px 1px;
|
||||
margin: 3px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
a:hover, h1 a:hover, h2 a:hover, .sectiontitle a:hover, #listScroller a:hover{
|
||||
background-color: #22D716;
|
||||
color: black;
|
||||
}
|
||||
|
||||
#browserBar a, .banner a {
|
||||
color: #D7FF00;
|
||||
}
|
||||
|
||||
#browserBar a:hover, .banner a:hover {
|
||||
background-color: #D7FF00;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
#listScroller a.activeA {
|
||||
background-color: #22D716;
|
||||
color: black ;
|
||||
border: 1px solid #ccc;
|
||||
padding: 0px 1px 1px 1px;
|
||||
}
|
||||
|
||||
#listScroller small{
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.activeTitle{
|
||||
font-family: monospace;
|
||||
font-size: large;
|
||||
border-bottom: 1px dashed black;
|
||||
margin-bottom: 0.3em;
|
||||
padding-bottom: 0.1em;
|
||||
background-color: #ffc;
|
||||
}
|
||||
|
||||
.activeMethod{
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
|
||||
.activeMethod .title {
|
||||
font-family: monospace;
|
||||
font-size: large;
|
||||
border-bottom: 1px dashed black;
|
||||
margin-bottom: 0.3em;
|
||||
padding-bottom: 0.1em;
|
||||
background-color: #ffa;
|
||||
}
|
||||
|
||||
.activeMethod .description, .activeMethod .sourcecode {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.activeMethod .sourcecode p.source-link {
|
||||
text-indent: 0em;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
.activeMethod .aka {
|
||||
margin-top: 0.3em;
|
||||
margin-left: 1em;
|
||||
font-style: italic;
|
||||
text-indent: 2em;
|
||||
}
|
||||
|
||||
#content {
|
||||
margin: 0.5em;
|
||||
}
|
||||
|
||||
#description p {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.sectiontitle {
|
||||
color: black;
|
||||
font-size: 28px;
|
||||
margin: 20px 0px;
|
||||
border-bottom: 2px solid #CCCCCC;
|
||||
|
||||
/* margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
padding: 0.5em;
|
||||
padding-left: 2em;
|
||||
background: #005;
|
||||
color: #FFF;
|
||||
font-weight: bold;
|
||||
border: 1px dotted black;*/
|
||||
}
|
||||
|
||||
.attr-rw {
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
text-align: center;
|
||||
color: #7AAD00;
|
||||
}
|
||||
|
||||
.attr-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.attr-desc {
|
||||
}
|
||||
|
||||
.attr-value {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.file-title-prefix {
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
.file-title {
|
||||
font-size: large;
|
||||
font-weight: bold;
|
||||
background: #005;
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
.banner {
|
||||
background: #888;
|
||||
color: #FFF;
|
||||
/* border: 1px solid black;*/
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.banner td {
|
||||
background: transparent;
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
.dyn-source {
|
||||
display: none;
|
||||
color: #000;
|
||||
border: 0px;
|
||||
border-left: 1px dotted #CCC;
|
||||
border-top: 1px dotted #CCC;
|
||||
margin: 0em;
|
||||
padding: 0em;
|
||||
}
|
||||
|
||||
.dyn-source .cmt {
|
||||
color: #7AAD00;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.dyn-source .kw {
|
||||
color: #11B716;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.method {
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
.description pre, .description td {
|
||||
font-family:"Courier",serif;
|
||||
}
|
||||
pre, .description pre {
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
color: white;
|
||||
padding: 12px;
|
||||
background: #222;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
h2.title, .method .title {
|
||||
color: #7AAD00;
|
||||
font-size: 22px;
|
||||
margin: 10px 0px;
|
||||
|
||||
/* font-size: large;
|
||||
border-bottom: 1px dashed black;
|
||||
margin: 0.3em;
|
||||
padding: 0.2em;
|
||||
*/}
|
||||
|
||||
.method .description, .method .sourcecode {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.description p, .sourcecode p {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.method .sourcecode p.source-link {
|
||||
text-indent: 0em;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
.method .aka {
|
||||
margin-top: 0.3em;
|
||||
margin-left: 1em;
|
||||
font-style: italic;
|
||||
text-indent: 2em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
padding: 1em;
|
||||
font-size: x-large;
|
||||
}
|
||||
|
||||
h2 {
|
||||
padding: 0.5em 1em 0.5em 1em;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: white;
|
||||
background-color: #868686;
|
||||
}
|
||||
|
||||
h3, h4, h5, h6 {
|
||||
padding: 0.2em 1em 0.2em 1em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.sourcecode > pre {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
border: 1px dotted black;
|
||||
background: #FFE;
|
||||
}
|
||||
|
||||
/* ============= */
|
||||
/* = home page = */
|
||||
/* ============= */
|
||||
|
||||
body#home {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#content {
|
||||
margin: 0 auto;
|
||||
width: 800px;
|
||||
}
|
||||
|
||||
#content h1.home {
|
||||
background-color: transparent;
|
||||
border:0pt none;
|
||||
color:#FFFFFF;
|
||||
font-size:36px;
|
||||
margin:20px 0px;
|
||||
padding: 0;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
#content #documentation-links h2.title {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
#documentation-links {
|
||||
background-color : white;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
#documentation-links p {
|
||||
margin: 22px;
|
||||
}
|
||||
|
||||
body#home #footer {
|
||||
background:#444444 none repeat scroll 0%;
|
||||
clear:both;
|
||||
}
|
||||
|
||||
#footer p {
|
||||
background-color: transparent;
|
||||
color:#999999;
|
||||
margin:0 auto;
|
||||
padding:12px;
|
||||
text-align:center;
|
||||
width: 800px;
|
||||
}
|
2515
web/doc/rdoc/generators/template/merb/prototype.js
vendored
Normal file
2515
web/doc/rdoc/generators/template/merb/prototype.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
1
web/log/merb.4000.pid
Normal file
1
web/log/merb.4000.pid
Normal file
|
@ -0,0 +1 @@
|
|||
31261
|
44
web/merb/merb-auth/setup.rb
Normal file
44
web/merb/merb-auth/setup.rb
Normal file
|
@ -0,0 +1,44 @@
|
|||
# This file is specifically setup for use with the merb-auth plugin.
|
||||
# This file should be used to setup and configure your authentication stack.
|
||||
# It is not required and may safely be deleted.
|
||||
#
|
||||
# To change the parameter names for the password or login field you may set either of these two options
|
||||
#
|
||||
# Merb::Plugins.config[:"merb-auth"][:login_param] = :email
|
||||
# Merb::Plugins.config[:"merb-auth"][:password_param] = :my_password_field_name
|
||||
|
||||
begin
|
||||
# Sets the default class ofr authentication. This is primarily used for
|
||||
# Plugins and the default strategies
|
||||
Merb::Authentication.user_class = User
|
||||
|
||||
|
||||
# Mixin the salted user mixin
|
||||
require 'merb-auth-more/mixins/salted_user'
|
||||
Merb::Authentication.user_class.class_eval{ include Merb::Authentication::Mixins::SaltedUser }
|
||||
|
||||
# Setup the session serialization
|
||||
class Merb::Authentication
|
||||
|
||||
def fetch_user(session_user_id)
|
||||
Merb::Authentication.user_class.get(session_user_id)
|
||||
end
|
||||
|
||||
def store_user(user)
|
||||
user.nil? ? user : user.id
|
||||
end
|
||||
end
|
||||
|
||||
rescue
|
||||
Merb.logger.error <<-TEXT
|
||||
|
||||
You need to setup some kind of user class with merb-auth.
|
||||
Merb::Authentication.user_class = User
|
||||
|
||||
If you want to fully customize your authentication you should use merb-core directly.
|
||||
|
||||
See merb/merb-auth/setup.rb and strategies.rb to customize your setup
|
||||
|
||||
TEXT
|
||||
end
|
||||
|
11
web/merb/merb-auth/strategies.rb
Normal file
11
web/merb/merb-auth/strategies.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
# This file is specifically for you to define your strategies
|
||||
#
|
||||
# You should declare you strategies directly and/or use
|
||||
# Merb::Authentication.activate!(:label_of_strategy)
|
||||
#
|
||||
# To load and set the order of strategy processing
|
||||
|
||||
Merb::Slices::config[:"merb-auth-slice-password"][:no_default_strategies] = true
|
||||
|
||||
Merb::Authentication.activate!(:default_password_form)
|
||||
Merb::Authentication.activate!(:default_basic_auth)
|
9
web/merb/session/session.rb
Normal file
9
web/merb/session/session.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
module Merb
|
||||
module Session
|
||||
|
||||
# The Merb::Session module gets mixed into Merb::SessionContainer to allow
|
||||
# app-level functionality; it will be included and methods will be available
|
||||
# through request.session as instance methods.
|
||||
|
||||
end
|
||||
end
|
17
web/public/.htaccess
Normal file
17
web/public/.htaccess
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Sets the default handler for FastCGI scripts
|
||||
AddHandler fastcgi-script .fcgi
|
||||
|
||||
# If Apache2 is used together with mod_fcgid,
|
||||
# uncomment the line below and comment in the line
|
||||
# above to set the correct script handler
|
||||
#AddHandler fcgid-script .fcgi
|
||||
|
||||
RewriteEngine On
|
||||
|
||||
RewriteRule ^$ index.html [QSA]
|
||||
RewriteRule ^([^.]+)$ $1.html [QSA]
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^(.*)$ merb.fcgi [QSA,L]
|
||||
|
||||
|
||||
ErrorDocument 500 "<h2>Application Error</h2>Merb could not be reached"
|
BIN
web/public/favicon.ico
Normal file
BIN
web/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
BIN
web/public/images/merb.jpg
Normal file
BIN
web/public/images/merb.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
1
web/public/javascripts/application.js
Normal file
1
web/public/javascripts/application.js
Normal file
|
@ -0,0 +1 @@
|
|||
// Common JavaScript code across your application goes here.
|
19
web/public/javascripts/jquery.js
vendored
Normal file
19
web/public/javascripts/jquery.js
vendored
Normal file
File diff suppressed because one or more lines are too long
22
web/public/merb.fcgi
Executable file
22
web/public/merb.fcgi
Executable file
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require 'rubygems'
|
||||
require 'merb-core'
|
||||
|
||||
# this is Merb.root, change this if you have some funky setup.
|
||||
merb_root = File.expand_path(File.dirname(__FILE__) / '../')
|
||||
|
||||
# If the fcgi process runs as apache, make sure
|
||||
# we have an inlinedir set for Rubyinline action-args to work
|
||||
unless ENV["INLINEDIR"] || ENV["HOME"]
|
||||
tmpdir = merb_root / "tmp"
|
||||
unless File.directory?(tmpdir)
|
||||
Dir.mkdir(tmpdir)
|
||||
end
|
||||
ENV["INLINEDIR"] = tmpdir
|
||||
end
|
||||
|
||||
# start merb with the fcgi adapter, add options or change the log dir here
|
||||
Merb.start(:adapter => 'fcgi',
|
||||
:merb_root => merb_root,
|
||||
:log_file => merb_root /'log'/'merb.log')
|
5
web/public/robots.txt
Normal file
5
web/public/robots.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
|
||||
#
|
||||
# To ban all spiders from the entire site uncomment the next two lines:
|
||||
# User-Agent: *
|
||||
# Disallow: /
|
119
web/public/stylesheets/master.css
Normal file
119
web/public/stylesheets/master.css
Normal file
|
@ -0,0 +1,119 @@
|
|||
body {
|
||||
font-family: Arial, Verdana, sans-serif;
|
||||
font-size: 12px;
|
||||
background-color: #fff;
|
||||
}
|
||||
* {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
text-decoration: none;
|
||||
}
|
||||
html {
|
||||
height: 100%;
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
#container {
|
||||
width: 80%;
|
||||
text-align: left;
|
||||
background-color: #fff;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
#header-container {
|
||||
width: 100%;
|
||||
padding-top: 15px;
|
||||
}
|
||||
#header-container h1, #header-container h2 {
|
||||
margin-left: 6px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.spacer {
|
||||
width: 100%;
|
||||
height: 15px;
|
||||
}
|
||||
hr {
|
||||
border: 0px;
|
||||
color: #ccc;
|
||||
background-color: #cdcdcd;
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
h1 {
|
||||
font-size: 28px;
|
||||
color: #c55;
|
||||
background-color: #fff;
|
||||
font-family: Arial, Verdana, sans-serif;
|
||||
font-weight: 300;
|
||||
}
|
||||
h2 {
|
||||
font-size: 15px;
|
||||
color: #999;
|
||||
font-family: Arial, Verdana, sans-serif;
|
||||
font-weight: 300;
|
||||
background-color: #fff;
|
||||
}
|
||||
h3 {
|
||||
color: #4d9b12;
|
||||
font-size: 15px;
|
||||
text-align: left;
|
||||
font-weight: 300;
|
||||
padding: 5px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
#left-container {
|
||||
float: left;
|
||||
width: 250px;
|
||||
background-color: #FFFFFF;
|
||||
color: black;
|
||||
}
|
||||
|
||||
#left-container h3 {
|
||||
color: #c55;
|
||||
}
|
||||
|
||||
#main-container {
|
||||
margin: 5px 5px 5px 260px;
|
||||
padding: 15px;
|
||||
border-left: 1px solid silver;
|
||||
min-height: 400px;
|
||||
}
|
||||
p {
|
||||
color: #000;
|
||||
background-color: #fff;
|
||||
line-height: 20px;
|
||||
padding: 5px;
|
||||
}
|
||||
a {
|
||||
color: #4d9b12;
|
||||
background-color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
color: #4d9b12;
|
||||
background-color: #fff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
#footer-container {
|
||||
clear: both;
|
||||
font-size: 12px;
|
||||
font-family: Verdana, Arial, sans-serif;
|
||||
}
|
||||
.right {
|
||||
float: right;
|
||||
font-size: 100%;
|
||||
margin-top: 5px;
|
||||
color: #999;
|
||||
background-color: #fff;
|
||||
}
|
||||
.left {
|
||||
float: left;
|
||||
font-size: 100%;
|
||||
margin-top: 5px;
|
||||
color: #999;
|
||||
background-color: #fff;
|
||||
}
|
||||
#main-container ul {
|
||||
margin-left: 3.0em;
|
||||
}
|
7
web/spec/requests/search_spec.rb
Normal file
7
web/spec/requests/search_spec.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')
|
||||
|
||||
describe "/search" do
|
||||
before(:each) do
|
||||
@response = request("/search")
|
||||
end
|
||||
end
|
0
web/spec/spec.opts
Normal file
0
web/spec/spec.opts
Normal file
25
web/spec/spec_helper.rb
Normal file
25
web/spec/spec_helper.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
require "rubygems"
|
||||
|
||||
# Add the local gems dir if found within the app root; any dependencies loaded
|
||||
# hereafter will try to load from the local gems before loading system gems.
|
||||
if (local_gem_dir = File.join(File.dirname(__FILE__), '..', 'gems')) && $BUNDLE.nil?
|
||||
$BUNDLE = true; Gem.clear_paths; Gem.path.unshift(local_gem_dir)
|
||||
end
|
||||
|
||||
require "merb-core"
|
||||
require "spec" # Satisfies Autotest and anyone else not using the Rake tasks
|
||||
|
||||
# this loads all plugins required in your init file so don't add them
|
||||
# here again, Merb will do it for you
|
||||
Merb.start_environment(:testing => true, :adapter => 'runner', :environment => ENV['MERB_ENV'] || 'test')
|
||||
|
||||
Spec::Runner.configure do |config|
|
||||
config.include(Merb::Test::ViewHelper)
|
||||
config.include(Merb::Test::RouteHelper)
|
||||
config.include(Merb::Test::ControllerHelper)
|
||||
|
||||
config.before(:all) do
|
||||
DataMapper.auto_migrate! if Merb.orm == :datamapper
|
||||
end
|
||||
|
||||
end
|
149
web/tasks/doc.thor
Normal file
149
web/tasks/doc.thor
Normal file
|
@ -0,0 +1,149 @@
|
|||
$: << File.join("doc")
|
||||
require 'rubygems'
|
||||
require 'rdoc/rdoc'
|
||||
require 'fileutils'
|
||||
require 'erb'
|
||||
|
||||
module Merb
|
||||
|
||||
class GemNotFoundException < Exception
|
||||
end
|
||||
|
||||
module DocMethods
|
||||
def setup_gem_path
|
||||
if File.directory?(gems_dir = File.join(File.dirname(__FILE__), 'gems'))
|
||||
$BUNDLE = true; Gem.clear_paths; Gem.path.unshift(gems_dir)
|
||||
end
|
||||
end
|
||||
|
||||
def get_more
|
||||
libs = []
|
||||
more_library = find_library("merb-more")
|
||||
File.open("#{more_library}/lib/merb-more.rb").read.each_line do |line|
|
||||
if line['require']
|
||||
libs << line.gsub("require '", '').gsub("'\n", '')
|
||||
end
|
||||
end
|
||||
return libs
|
||||
end
|
||||
|
||||
def generate_documentation(file_list, destination, arguments = [])
|
||||
output_dir = File.join("/../doc", "rdoc", destination)
|
||||
FileUtils.rm_rf(output_dir)
|
||||
|
||||
arguments += [
|
||||
"--fmt", "merb",
|
||||
"--op", output_dir
|
||||
]
|
||||
RDoc::RDoc.new.document(arguments + file_list)
|
||||
AdvancedDoc.new.index
|
||||
end
|
||||
|
||||
def find_library(directory_snippet)
|
||||
gem_dir = nil
|
||||
Gem.path.find do |path|
|
||||
dir = Dir.glob("#{path}/gems/#{directory_snippet}*")
|
||||
dir.empty? ? false : gem_dir = dir.last
|
||||
end
|
||||
raise GemNotFoundException if gem_dir.nil?
|
||||
return gem_dir
|
||||
end
|
||||
|
||||
def get_file_list(directory_snippet)
|
||||
gem_dir = find_library(directory_snippet)
|
||||
files = Dir.glob("#{gem_dir}/**/lib/**/*.rb")
|
||||
files += ["#{gem_dir}/README"] if File.exists?("#{gem_dir}/README")
|
||||
return files
|
||||
end
|
||||
end
|
||||
|
||||
class AdvancedDoc < Thor
|
||||
|
||||
group 'core'
|
||||
include DocMethods
|
||||
|
||||
def initialize
|
||||
super
|
||||
setup_gem_path
|
||||
end
|
||||
|
||||
desc 'index', "Regenerate the index file for your framework documentation"
|
||||
def index
|
||||
@directories = Dir.entries(File.join(File.dirname(__FILE__) + "/../", "doc", "rdoc"))
|
||||
@directories.delete(".")
|
||||
@directories.delete("..")
|
||||
@directories.delete("generators")
|
||||
@directories.delete("index.html")
|
||||
index_template = File.read(File.join("doc", "rdoc", "generators", "template", "merb", "index.html.erb"))
|
||||
|
||||
File.open(File.join("doc", "rdoc", "index.html"), "w") do |file|
|
||||
file.write(ERB.new(index_template).result(binding))
|
||||
end
|
||||
end
|
||||
|
||||
desc 'plugins', 'Generate the rdoc for each merb-plugins seperatly'
|
||||
def plugins
|
||||
libs = ["merb_activerecord", "merb_builder", "merb_jquery", "merb_laszlo", "merb_parts", "merb_screw_unit", "merb_sequel", "merb_stories", "merb_test_unit"]
|
||||
|
||||
libs.each do |lib|
|
||||
options[:gem] = lib
|
||||
gem
|
||||
end
|
||||
end
|
||||
|
||||
desc 'more', 'Generate the rdoc for each merb-more gem seperatly'
|
||||
def more
|
||||
libs = get_more
|
||||
libs.each do |lib|
|
||||
options[:gem] = lib
|
||||
gem
|
||||
end
|
||||
end
|
||||
|
||||
desc 'core', 'Generate the rdoc for merb-core'
|
||||
def core
|
||||
options[:gem] = "merb-core"
|
||||
gem
|
||||
end
|
||||
|
||||
desc 'gem', 'Generate the rdoc for a specific gem'
|
||||
method_options "--gem" => :required
|
||||
def gem
|
||||
file_list = get_file_list(options[:gem])
|
||||
readme = File.join(find_library("merb-core"), "README")
|
||||
generate_documentation(file_list, options[:gem], ["-m", readme])
|
||||
rescue GemNotFoundException
|
||||
puts "Can not find the gem in the gem path #{options[:gem]}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Doc < Thor
|
||||
|
||||
include DocMethods
|
||||
|
||||
def initialize
|
||||
super
|
||||
setup_gem_path
|
||||
|
||||
end
|
||||
|
||||
desc 'stack', 'Generate the rdoc for merb-core, merb-more merged together'
|
||||
def stack
|
||||
libs = ["merb"]
|
||||
|
||||
file_list = []
|
||||
libs.each do |gem_name|
|
||||
begin
|
||||
file_list += get_file_list(gem_name)
|
||||
rescue GemNotFoundException
|
||||
puts "Could not find #{gem_name} in #{Gem.path}. Continuing with out it."
|
||||
end
|
||||
end
|
||||
readme = File.join(find_library("merb"), "README")
|
||||
generate_documentation(file_list, "stack", ["-m", readme])
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
31
web/tasks/merb.thor/app_script.rb
Normal file
31
web/tasks/merb.thor/app_script.rb
Normal file
|
@ -0,0 +1,31 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
# This was added by Merb's bundler
|
||||
|
||||
require "rubygems"
|
||||
require File.join(File.dirname(__FILE__), "common")
|
||||
|
||||
gems_dir = File.join(File.dirname(__FILE__), '..', 'gems')
|
||||
|
||||
if File.directory?(gems_dir)
|
||||
$BUNDLE = true
|
||||
Gem.clear_paths
|
||||
Gem.path.replace([File.expand_path(gems_dir)])
|
||||
ENV["PATH"] = "#{File.dirname(__FILE__)}:#{ENV["PATH"]}"
|
||||
|
||||
gem_file = File.join(gems_dir, "specifications", "<%= spec.name %>-*.gemspec")
|
||||
|
||||
if local_gem = Dir[gem_file].last
|
||||
version = File.basename(local_gem)[/-([\.\d]+)\.gemspec$/, 1]
|
||||
end
|
||||
end
|
||||
|
||||
version ||= "<%= Gem::Requirement.default %>"
|
||||
|
||||
if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
|
||||
version = $1
|
||||
ARGV.shift
|
||||
end
|
||||
|
||||
gem '<%= @spec.name %>', version
|
||||
load '<%= bin_file_name %>'
|
68
web/tasks/merb.thor/common.rb
Normal file
68
web/tasks/merb.thor/common.rb
Normal file
|
@ -0,0 +1,68 @@
|
|||
# This was added via Merb's bundler
|
||||
|
||||
require "rubygems"
|
||||
require "rubygems/source_index"
|
||||
|
||||
module Gem
|
||||
BUNDLED_SPECS = File.join(Dir.pwd, "gems", "specifications")
|
||||
MAIN_INDEX = Gem::SourceIndex.from_gems_in(BUNDLED_SPECS)
|
||||
FALLBACK_INDEX = Gem::SourceIndex.from_installed_gems
|
||||
|
||||
def self.source_index
|
||||
MultiSourceIndex.new
|
||||
end
|
||||
|
||||
def self.searcher
|
||||
MultiPathSearcher.new
|
||||
end
|
||||
|
||||
class ArbitrarySearcher < GemPathSearcher
|
||||
def initialize(source_index)
|
||||
@source_index = source_index
|
||||
super()
|
||||
end
|
||||
|
||||
def init_gemspecs
|
||||
@source_index.map { |_, spec| spec }.sort { |a,b|
|
||||
(a.name <=> b.name).nonzero? || (b.version <=> a.version)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
class MultiPathSearcher
|
||||
def initialize
|
||||
@main_searcher = ArbitrarySearcher.new(MAIN_INDEX)
|
||||
@fallback_searcher = ArbitrarySearcher.new(FALLBACK_INDEX)
|
||||
end
|
||||
|
||||
def find(path)
|
||||
try = @main_searcher.find(path)
|
||||
return try if try
|
||||
@fallback_searcher.find(path)
|
||||
end
|
||||
|
||||
def find_all(path)
|
||||
try = @main_searcher.find_all(path)
|
||||
return try unless try.empty?
|
||||
@fallback_searcher.find_all(path)
|
||||
end
|
||||
end
|
||||
|
||||
class MultiSourceIndex
|
||||
# Used by merb.thor to confirm; not needed when MSI is in use
|
||||
def load_gems_in(*args)
|
||||
end
|
||||
|
||||
def search(*args)
|
||||
try = MAIN_INDEX.search(*args)
|
||||
return try unless try.empty?
|
||||
FALLBACK_INDEX.search(*args)
|
||||
end
|
||||
|
||||
def find_name(*args)
|
||||
try = MAIN_INDEX.find_name(*args)
|
||||
return try unless try.empty?
|
||||
FALLBACK_INDEX.find_name(*args)
|
||||
end
|
||||
end
|
||||
end
|
125
web/tasks/merb.thor/gem_ext.rb
Normal file
125
web/tasks/merb.thor/gem_ext.rb
Normal file
|
@ -0,0 +1,125 @@
|
|||
require "erb"
|
||||
|
||||
Gem.pre_install_hooks.push(proc do |installer|
|
||||
unless File.file?(installer.bin_dir / "common.rb")
|
||||
FileUtils.mkdir_p(installer.bin_dir)
|
||||
FileUtils.cp(File.dirname(__FILE__) / "common.rb", installer.bin_dir / "common.rb")
|
||||
end
|
||||
|
||||
include ColorfulMessages
|
||||
name = installer.spec.name
|
||||
if $GEMS && versions = ($GEMS.assoc(name) || [])[1]
|
||||
dep = Gem::Dependency.new(name, versions)
|
||||
unless dep.version_requirements.satisfied_by?(installer.spec.version)
|
||||
error "Cannot install #{installer.spec.full_name} " \
|
||||
"for #{$INSTALLING}; " \
|
||||
"you required #{dep}"
|
||||
::Thor::Tasks::Merb::Gem.rollback_trans
|
||||
exit!
|
||||
end
|
||||
end
|
||||
success "Installing #{installer.spec.full_name}"
|
||||
end)
|
||||
|
||||
class ::Gem::Uninstaller
|
||||
def self._with_silent_ui
|
||||
|
||||
ui = Gem::DefaultUserInteraction.ui
|
||||
def ui.say(str)
|
||||
puts "- #{str}"
|
||||
end
|
||||
|
||||
yield
|
||||
|
||||
class << Gem::DefaultUserInteraction.ui
|
||||
remove_method :say
|
||||
end
|
||||
end
|
||||
|
||||
def self._uninstall(source_index, name, op, version)
|
||||
unless source_index.find_name(name, "#{op} #{version}").empty?
|
||||
uninstaller = Gem::Uninstaller.new(
|
||||
name,
|
||||
:version => "#{op} #{version}",
|
||||
:install_dir => Dir.pwd / "gems",
|
||||
:all => true,
|
||||
:ignore => true
|
||||
)
|
||||
_with_silent_ui { uninstaller.uninstall }
|
||||
end
|
||||
end
|
||||
|
||||
def self._uninstall_others(source_index, name, version)
|
||||
_uninstall(source_index, name, "<", version)
|
||||
_uninstall(source_index, name, ">", version)
|
||||
end
|
||||
end
|
||||
|
||||
Gem.post_install_hooks.push(proc do |installer|
|
||||
source_index = installer.instance_variable_get("@source_index")
|
||||
::Gem::Uninstaller._uninstall_others(
|
||||
source_index, installer.spec.name, installer.spec.version
|
||||
)
|
||||
end)
|
||||
|
||||
class ::Gem::DependencyInstaller
|
||||
alias old_fg find_gems_with_sources
|
||||
|
||||
def find_gems_with_sources(dep)
|
||||
if @source_index.any? { |_, installed_spec|
|
||||
installed_spec.satisfies_requirement?(dep)
|
||||
}
|
||||
return []
|
||||
end
|
||||
|
||||
old_fg(dep)
|
||||
end
|
||||
end
|
||||
|
||||
class ::Gem::SpecFetcher
|
||||
alias old_fetch fetch
|
||||
def fetch(dependency, all = false, matching_platform = true)
|
||||
idx = Gem::SourceIndex.from_installed_gems
|
||||
|
||||
reqs = dependency.version_requirements.requirements
|
||||
|
||||
if reqs.size == 1 && reqs[0][0] == "="
|
||||
dep = idx.search(dependency).sort.last
|
||||
end
|
||||
|
||||
if dep
|
||||
file = dep.loaded_from.dup
|
||||
file.gsub!(/specifications/, "cache")
|
||||
file.gsub!(/gemspec$/, "gem")
|
||||
spec = ::Gem::Format.from_file_by_path(file).spec
|
||||
[[spec, file]]
|
||||
else
|
||||
old_fetch(dependency, all, matching_platform)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ::Gem::Installer
|
||||
def app_script_text(bin_file_name)
|
||||
template = File.read(File.dirname(__FILE__) / "app_script.rb")
|
||||
erb = ERB.new(template)
|
||||
erb.result(binding)
|
||||
end
|
||||
end
|
||||
|
||||
class ::Gem::Specification
|
||||
def recursive_dependencies(from, index = Gem.source_index)
|
||||
specs = self.runtime_dependencies.map do |dep|
|
||||
spec = index.search(dep).last
|
||||
unless spec
|
||||
from_name = from.is_a?(::Gem::Specification) ? from.full_name : from.to_s
|
||||
wider_net = index.find_name(dep.name).last
|
||||
ThorUI.error "Needed #{dep} for #{from_name}, but could not find it"
|
||||
ThorUI.error "Found #{wider_net.full_name}" if wider_net
|
||||
::Thor::Tasks::Merb::Gem.rollback_trans
|
||||
end
|
||||
spec
|
||||
end
|
||||
specs + specs.map {|s| s.recursive_dependencies(self, index)}.flatten.uniq
|
||||
end
|
||||
end
|
150
web/tasks/merb.thor/main.thor
Normal file
150
web/tasks/merb.thor/main.thor
Normal file
|
@ -0,0 +1,150 @@
|
|||
require "rubygems"
|
||||
require "rubygems/source_index"
|
||||
require "rubygems/dependency_installer"
|
||||
require "rubygems/uninstaller"
|
||||
require "fileutils"
|
||||
require File.join(File.dirname(__FILE__), "utils")
|
||||
require File.join(File.dirname(__FILE__), "gem_ext")
|
||||
require File.join(File.dirname(__FILE__), "ops")
|
||||
|
||||
$INSTALLING = []
|
||||
|
||||
module Merb
|
||||
|
||||
class Gem < Thor
|
||||
extend ColorfulMessages
|
||||
|
||||
def initialize
|
||||
dirs = [Dir.pwd, File.dirname(__FILE__) / ".."]
|
||||
root = dirs.find {|d| File.file?(d / "config" / "dependencies.rb")}
|
||||
|
||||
if root
|
||||
@depsrb = root / "config" / "dependencies.rb"
|
||||
else
|
||||
self.class.error "dependencies.rb was not found"
|
||||
exit!
|
||||
end
|
||||
|
||||
FileUtils.mkdir_p(Dir.pwd / "gems")
|
||||
|
||||
@list = Collector.collect(File.read(@depsrb))
|
||||
@idx = ::Gem::SourceIndex.new.load_gems_in("gems/specifications")
|
||||
end
|
||||
|
||||
def list
|
||||
require "pp"
|
||||
pp @list
|
||||
end
|
||||
|
||||
desc "redeploy", "Syncs up gems/cache with gems/gems. All gems in the cache " \
|
||||
"that are not already installed will be installed from the " \
|
||||
"cache. All installed gems that are not in the cache will " \
|
||||
"be uninstalled."
|
||||
def redeploy
|
||||
gem_dir = Dir.pwd / "gems" / "gems"
|
||||
cache_dir = Dir.pwd / "gems" / "cache"
|
||||
|
||||
gems = Dir[gem_dir / "*"].map! {|n| File.basename(n)}
|
||||
cache = Dir[cache_dir / "*.gem"].map! {|n| File.basename(n, ".gem")}
|
||||
new_gems = cache - gems
|
||||
outdated = gems - cache
|
||||
idx = ::Gem::SourceIndex.new
|
||||
idx.load_gems_in(Dir.pwd / "gems" / "specifications")
|
||||
|
||||
new_gems.each do |g|
|
||||
installer = ::Gem::Installer.new(cache_dir / "#{g}.gem",
|
||||
:bin_dir => Dir.pwd / "bin",
|
||||
:install_dir => Dir.pwd / "gems",
|
||||
:ignore_dependencies => true,
|
||||
:user_install => false,
|
||||
:wrappers => true,
|
||||
:source_index => idx)
|
||||
|
||||
installer.install
|
||||
end
|
||||
|
||||
outdated.each do |g|
|
||||
/(.*)\-(.*)/ =~ g
|
||||
name, version = $1, $2
|
||||
uninstaller = ::Gem::Uninstaller.new(name,
|
||||
:version => version,
|
||||
:bin_dir => Dir.pwd / "bin",
|
||||
:install_dir => Dir.pwd / "gems",
|
||||
:ignore => true,
|
||||
:executables => true
|
||||
)
|
||||
uninstaller.uninstall
|
||||
end
|
||||
end
|
||||
|
||||
desc "confirm", "Confirm the current setup. merb:gem:install will " \
|
||||
"automatically run this task before committing the " \
|
||||
"changes it makes."
|
||||
def confirm(gems = @list)
|
||||
::Gem.path.replace([Dir.pwd / "gems"])
|
||||
::Gem.source_index.load_gems_in(Dir.pwd / "gems" / "specifications")
|
||||
|
||||
self.class.info "Confirming configuration..."
|
||||
|
||||
::Gem.loaded_specs.clear
|
||||
|
||||
begin
|
||||
gems.each do |name, versions|
|
||||
versions ||= []
|
||||
::Gem.activate name, *versions
|
||||
end
|
||||
rescue ::Gem::LoadError => e
|
||||
self.class.error "Configuration could not be confirmed: #{e.message}"
|
||||
self.class.rollback_trans
|
||||
end
|
||||
self.class.info "Confirmed"
|
||||
end
|
||||
|
||||
desc 'install', 'Sync up your bundled gems with the list in config/dependencies.rb'
|
||||
def install(*gems)
|
||||
if gems.empty?
|
||||
gems = @list
|
||||
else
|
||||
gems = gems.map {|desc| name, *versions = desc.split(" ") }
|
||||
end
|
||||
|
||||
$GEMS = gems
|
||||
|
||||
self.class.begin_trans
|
||||
|
||||
gems.each do |name, versions|
|
||||
dep = ::Gem::Dependency.new(name, versions || [])
|
||||
unless @idx.search(dep).empty?
|
||||
next
|
||||
end
|
||||
|
||||
rescue_failures do
|
||||
$INSTALLING = dep
|
||||
_install(dep)
|
||||
end
|
||||
end
|
||||
|
||||
gem_dir = Dir.pwd / "gems" / "gems"
|
||||
installed_gems = Dir[gem_dir / "*"].map! {|n| File.basename(n)}
|
||||
|
||||
list = full_list.map {|x| x.full_name}.compact
|
||||
|
||||
(installed_gems - list).each do |g|
|
||||
/^(.*)\-(.*)$/ =~ g
|
||||
name, version = $1, $2
|
||||
uninstaller = ::Gem::Uninstaller.new(name,
|
||||
:version => version,
|
||||
:bin_dir => (Dir.pwd / "bin").to_s,
|
||||
:install_dir => (Dir.pwd / "gems").to_s,
|
||||
:ignore => true,
|
||||
:executables => true
|
||||
)
|
||||
uninstaller.uninstall
|
||||
end
|
||||
|
||||
confirm(gems)
|
||||
|
||||
self.class.commit_trans
|
||||
end
|
||||
end
|
||||
end
|
93
web/tasks/merb.thor/ops.rb
Normal file
93
web/tasks/merb.thor/ops.rb
Normal file
|
@ -0,0 +1,93 @@
|
|||
module Thor::Tasks
|
||||
module Merb
|
||||
class Collector
|
||||
attr_reader :dependencies
|
||||
|
||||
def self.collect(str)
|
||||
collector = new
|
||||
collector.instance_eval(str)
|
||||
collector.dependencies
|
||||
end
|
||||
|
||||
def initialize
|
||||
@dependencies = []
|
||||
end
|
||||
|
||||
def dependency(name, *versions)
|
||||
versions.pop if versions.last.is_a?(Hash)
|
||||
@dependencies << [name, versions]
|
||||
end
|
||||
end
|
||||
|
||||
class Gem < Thor
|
||||
def full_list
|
||||
@idx.load_gems_in("gems/specifications")
|
||||
|
||||
@list.map do |name, versions|
|
||||
dep = ::Gem::Dependency.new(name, versions)
|
||||
spec = @idx.search(dep).last
|
||||
unless spec
|
||||
self.class.error "A required dependency #{dep} was not found"
|
||||
self.class.rollback_trans
|
||||
end
|
||||
deps = spec.recursive_dependencies(dep, @idx)
|
||||
[spec] + deps
|
||||
end.flatten.uniq
|
||||
end
|
||||
|
||||
def rescue_failures(error = StandardError, prc = nil)
|
||||
begin
|
||||
yield
|
||||
rescue error => e
|
||||
if prc
|
||||
prc.call(e)
|
||||
else
|
||||
puts e.message
|
||||
puts e.backtrace
|
||||
end
|
||||
self.class.rollback_trans
|
||||
end
|
||||
end
|
||||
|
||||
def self.begin_trans
|
||||
note "Beginning transaction"
|
||||
FileUtils.cp_r(Dir.pwd / "gems", Dir.pwd / ".original_gems")
|
||||
end
|
||||
|
||||
def self.commit_trans
|
||||
note "Committing transaction"
|
||||
FileUtils.rm_rf(Dir.pwd / ".original_gems")
|
||||
end
|
||||
|
||||
def self.rollback_trans
|
||||
if File.exist?(Dir.pwd / ".original_gems")
|
||||
note "Rolling back transaction"
|
||||
FileUtils.rm_rf(Dir.pwd / "gems")
|
||||
FileUtils.mv(Dir.pwd / ".original_gems", Dir.pwd / "gems")
|
||||
end
|
||||
exit!
|
||||
end
|
||||
|
||||
private
|
||||
def _install(dep)
|
||||
@idx.load_gems_in("gems/specifications")
|
||||
return if @idx.search(dep).last
|
||||
|
||||
installer = ::Gem::DependencyInstaller.new(
|
||||
:bin_dir => Dir.pwd / "bin",
|
||||
:install_dir => Dir.pwd / "gems",
|
||||
:user_install => false)
|
||||
|
||||
begin
|
||||
installer.install dep.name, dep.version_requirements
|
||||
rescue ::Gem::GemNotFoundException => e
|
||||
puts "Cannot find #{dep}"
|
||||
rescue ::Gem::RemoteFetcher::FetchError => e
|
||||
puts e.message
|
||||
puts "Retrying..."
|
||||
retry
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
40
web/tasks/merb.thor/utils.rb
Normal file
40
web/tasks/merb.thor/utils.rb
Normal file
|
@ -0,0 +1,40 @@
|
|||
class String
|
||||
def /(other)
|
||||
(Pathname.new(self) + other).to_s
|
||||
end
|
||||
end
|
||||
|
||||
module ColorfulMessages
|
||||
|
||||
# red
|
||||
def error(*messages)
|
||||
puts messages.map { |msg| "\033[1;31m#{msg}\033[0m" }
|
||||
end
|
||||
|
||||
# yellow
|
||||
def warning(*messages)
|
||||
puts messages.map { |msg| "\033[1;33m#{msg}\033[0m" }
|
||||
end
|
||||
|
||||
# green
|
||||
def success(*messages)
|
||||
puts messages.map { |msg| "\033[1;32m#{msg}\033[0m" }
|
||||
end
|
||||
|
||||
alias_method :message, :success
|
||||
|
||||
# magenta
|
||||
def note(*messages)
|
||||
puts messages.map { |msg| "\033[1;35m#{msg}\033[0m" }
|
||||
end
|
||||
|
||||
# blue
|
||||
def info(*messages)
|
||||
puts messages.map { |msg| "\033[1;34m#{msg}\033[0m" }
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
module ThorUI
|
||||
extend ColorfulMessages
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue