tap-server 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. data/History +4 -0
  2. data/MIT-LICENSE +17 -15
  3. data/README +2 -11
  4. data/cmd/server.rb +27 -41
  5. data/lib/tap/controller.rb +22 -31
  6. data/lib/tap/controllers/app.rb +20 -116
  7. data/lib/tap/controllers/data.rb +16 -1
  8. data/lib/tap/controllers/server.rb +58 -15
  9. data/lib/tap/generator/generators/controller.rb +23 -0
  10. data/lib/tap/server.rb +75 -53
  11. data/lib/tap/tasks/echo.rb +1 -1
  12. data/templates/tap/generator/generators/controller/resource.erb +14 -0
  13. data/templates/tap/generator/generators/controller/test.erb +0 -0
  14. data/templates/tap/generator/generators/controller/view.erb +1 -0
  15. data/views/configurable/configurations.erb +57 -0
  16. data/views/configurable/default.erb +1 -0
  17. data/views/layout.erb +5 -2
  18. data/views/tap/{task → app/api}/help.erb +6 -4
  19. data/views/tap/controller/help.erb +4 -2
  20. data/views/tap/controllers/app/index.erb +47 -0
  21. data/views/tap/controllers/data/_upload.erb +1 -1
  22. data/views/tap/controllers/data/index.erb +16 -5
  23. data/views/tap/controllers/server/index.erb +10 -33
  24. data/views/tap/signals/signal/get.erb +1 -0
  25. data/views/tap/signals/signal/index.erb +4 -0
  26. data/views/tap/signals/signal/post.erb +1 -0
  27. metadata +18 -26
  28. data/lib/tap/controllers/schema.rb +0 -202
  29. data/lib/tap/server/runner.rb +0 -71
  30. data/public/javascripts/prototype.js +0 -4221
  31. data/public/javascripts/tap.js +0 -112
  32. data/views/configurable/_configs.erb +0 -33
  33. data/views/configurable/_flag.erb +0 -2
  34. data/views/configurable/_list_select.erb +0 -6
  35. data/views/configurable/_select.erb +0 -5
  36. data/views/configurable/_switch.erb +0 -2
  37. data/views/tap/controllers/app/_action.erb +0 -3
  38. data/views/tap/controllers/app/build.erb +0 -18
  39. data/views/tap/controllers/app/enque.erb +0 -13
  40. data/views/tap/controllers/app/info.erb +0 -21
  41. data/views/tap/controllers/app/tail.erb +0 -8
  42. data/views/tap/controllers/data/_index_entry.erb +0 -1
  43. data/views/tap/controllers/schema/_build.erb +0 -6
  44. data/views/tap/controllers/schema/_index_entry.erb +0 -6
  45. data/views/tap/controllers/schema/entry.erb +0 -144
  46. data/views/tap/task/input.erb +0 -17
  47. data/views/tap/tasks/load/input.erb +0 -11
@@ -61,6 +61,7 @@ module Tap
61
61
  # POST /projects?_method=put&id=id
62
62
  def destroy(id)
63
63
  data.destroy(type, id)
64
+ deselect([id])
64
65
  redirect uri
65
66
  end
66
67
 
@@ -72,7 +73,21 @@ module Tap
72
73
  end
73
74
 
74
75
  def select(ids=[])
75
- data.cache[type] = ids
76
+ current = data.cache[type] ||= []
77
+ data.cache[type] = current | ids
78
+ redirect uri
79
+ end
80
+
81
+ def deselect(ids=[])
82
+ if current = data.cache[type]
83
+ data.cache[type] = current - ids
84
+ end
85
+ redirect uri
86
+ end
87
+
88
+ def destroy_all(ids=[])
89
+ ids.each {|id| data.destroy(type, id) }
90
+ deselect(ids)
76
91
  redirect uri
77
92
  end
78
93
 
@@ -16,7 +16,24 @@ module Tap
16
16
  include Utils
17
17
 
18
18
  def index
19
- render('index.erb', :layout => true)
19
+ env = server.env
20
+ env_keys = env.minihash(true)
21
+ constants = env.constants
22
+ manifests = env.collect do |current|
23
+ types = {}
24
+ constants.entries(current).minimap.each do |key, const|
25
+ const.types.keys.each do |type|
26
+ (types[type] ||= []) << [key, const]
27
+ end
28
+ end
29
+
30
+ types = types.to_a.sort_by {|type, minimap| type }
31
+ types.empty? ? nil : [env_keys[current], types]
32
+ end
33
+
34
+ render 'index.erb', :locals => {
35
+ :manifests => manifests.compact
36
+ }, :layout => true
20
37
  end
21
38
 
22
39
  # Returns pong
@@ -55,11 +72,12 @@ module Tap
55
72
  end
56
73
  end
57
74
 
58
- def help(type=nil, *key)
59
- if constant = server.env[type][key.join('/')]
60
- module_render 'help.erb', constant
75
+ def help(*key)
76
+ if constant = server.env[key.join('/')]
77
+ path = server.module_path('help.erb', constant)
78
+ render :file => path, :locals => {:obj => constant}
61
79
  else
62
- "unknown #{type}: #{key.join('/')}"
80
+ "unknown constant: #{key.join('/')}"
63
81
  end
64
82
  end
65
83
 
@@ -67,11 +85,31 @@ module Tap
67
85
  set :define_action, false
68
86
 
69
87
  def call(rack_env)
70
- path = rack_env['tap.server'].env.path(:public, rack_env['PATH_INFO']) {|file| File.file?(file) }
71
- if path
72
- static_file(path)
88
+ server = rack_env['tap.server']
89
+ env = server ? server.env : nil
90
+ path_info = rack_env['PATH_INFO']
91
+
92
+ # serve static files
93
+ path = env.path(:public, path_info) {|file| File.file?(file) }
94
+ return static_file(path) if path
95
+
96
+ # route to a controller
97
+ blank, path, path_info = path_info.split("/", 3)
98
+ constant = env ? env.constants.seek(unescape(path)) : nil
99
+
100
+ if constant
101
+ # adjust rack_env if route routes to a controller
102
+ rack_env['SCRIPT_NAME'] = "#{rack_env['SCRIPT_NAME'].chomp('/')}/#{path}"
103
+ rack_env['PATH_INFO'] = "/#{path_info}"
104
+
105
+ constant.unload if server.development
106
+ controller = constant.constantize
107
+ controller == Server ? super : controller.call(rack_env)
73
108
  else
74
- super
109
+ response = Rack::Response.new
110
+ response.status = 302
111
+ response['Location'] = ["/server#{rack_env['PATH_INFO']}".chomp("/")]
112
+ response.finish
75
113
  end
76
114
  end
77
115
 
@@ -87,15 +125,20 @@ module Tap
87
125
  end
88
126
 
89
127
  # Returns a help uri for the specified resource, currently only sketched out.
90
- def help_uri(type, key)
91
- uri("help/#{type}/#{key}")
128
+ def help_uri(key)
129
+ uri("help/#{key}")
92
130
  end
93
131
 
94
- # Stops the server.
95
- def stop!
96
- server.stop!
132
+ def template
133
+ %Q{<% if !minimap.empty? && count > 1 %>
134
+ <h2><%= env_key %></h2>
135
+ <li>
136
+ <ul><% minimap.each do |key, entry| %>
137
+ <li><%= key %> (<a href="help/<%= key %>">?</a>)</li><% end %>
138
+ </ul>
139
+ </li>
140
+ <% end %>}
97
141
  end
98
-
99
142
  end
100
143
  end
101
144
  end
@@ -0,0 +1,23 @@
1
+ require 'tap/generator/generators/resource'
2
+
3
+ module Tap
4
+ module Generator
5
+ module Generators
6
+ # :startdoc::generator generates a controller
7
+ #
8
+ # Generates a new Tap::Controller and an associated test file.
9
+ class Controller < Resource
10
+
11
+ def manifest(m, const_name)
12
+ const = super
13
+
14
+ views_dir = path('views', "#{const.path}")
15
+ m.directory File.dirname(views_dir)
16
+ m.template path(views_dir, "index.erb"), "view.erb"
17
+
18
+ const
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,12 +1,20 @@
1
+ require 'rack'
1
2
  require 'tap'
2
3
  require 'tap/server/data'
3
- require 'tap/server/runner'
4
4
  require 'tap/server/server_error'
5
5
 
6
6
  module Tap
7
7
  # ::configurable
8
8
  class Server
9
- include Runner
9
+ include Rack::Utils
10
+ include Configurable
11
+
12
+ config :servers, %w[thin mongrel webrick], # the server handlers
13
+ :long => :server,
14
+ &c.list
15
+
16
+ config :host, '127.0.0.1', &c.string # the server host
17
+ config :port, 8080, &c.integer_or_nil # the server port
10
18
 
11
19
  # Server implements a secret for HTTP administration of the server (ex
12
20
  # remote shutdown). Under many circumstances this functionality is
@@ -16,22 +24,34 @@ module Tap
16
24
 
17
25
  config :development, false, &c.flag
18
26
 
19
- config :router, true, &c.switch
20
-
21
- nest :env, Tap::Env, :type => :hidden
22
-
23
- nest :app, Tap::App, :type => :hidden
24
-
25
27
  nest :data, Data, :type => :hidden
26
28
 
27
- attr_accessor :controller
29
+ attr_reader :app
30
+ attr_reader :controller
28
31
 
29
- attr_accessor :thread
32
+ def initialize(config={}, app=Tap::App.instance, &block)
33
+ @handler = nil
34
+ @controller = block
35
+
36
+ @app = app
37
+ initialize_config(config)
38
+ end
39
+
40
+ def env
41
+ app.env
42
+ end
30
43
 
31
- def initialize(controller=nil, config={})
44
+ def bind(controller)
45
+ if controller.kind_of?(String)
46
+ controller = app.resolve(controller)
47
+ end
48
+
49
+ unless controller.respond_to?(:call)
50
+ raise "invalid controller: #{controller.inspect}"
51
+ end
52
+
32
53
  @controller = controller
33
- @thread = nil
34
- super(config)
54
+ self
35
55
  end
36
56
 
37
57
  # Returns true if input is equal to the secret, if a secret is set. Used
@@ -41,36 +61,18 @@ module Tap
41
61
  secret != nil && input == secret
42
62
  end
43
63
 
44
- def route(rack_env)
45
- return controller unless router
46
-
47
- # route to a controller
48
- blank, path, path_info = rack_env['PATH_INFO'].split("/", 3)
49
- controller = lookup_controller(unescape(path))
50
-
51
- if controller
52
- # adjust rack_env if route routes to a controller
53
- rack_env['SCRIPT_NAME'] = ["#{rack_env['SCRIPT_NAME'].chomp('/')}/#{path}"]
54
- rack_env['PATH_INFO'] = ["/#{path_info}"]
55
- else
56
- # use default controller
57
- controller = self.controller
58
- path = nil
59
- end
60
-
61
- rack_env['tap.controller_path'] = path
62
- controller
64
+ def template_path(path)
65
+ app.env.path(:views, path) {|file| File.file?(file) }
63
66
  end
64
-
67
+
68
+ def module_path(path, klass)
69
+ app.env.module_path(:views, klass.ancestors, path) {|file| File.file?(file) }
70
+ end
71
+
65
72
  # The {Rack}[http://rack.rubyforge.org/doc/] interface method.
66
73
  def call(rack_env)
67
74
  # handle the request
68
75
  rack_env['tap.server'] = self
69
-
70
- unless controller = route(rack_env)
71
- raise ServerError.new("404 Error: could not route to controller", 404)
72
- end
73
-
74
76
  controller.call(rack_env)
75
77
  rescue ServerError
76
78
  $!.response
@@ -78,27 +80,47 @@ module Tap
78
80
  ServerError.response($!)
79
81
  end
80
82
 
81
- def run!
82
- super(self)
83
+ # Runs self as configured, on the specified server, host, and port. Use an
84
+ # INT signal to interrupt.
85
+ def run!(handler=rack_handler)
86
+ return self if @handler
87
+
88
+ handler.run(self, :Host => host, :Port => port) do |handler|
89
+ @handler = handler
90
+ trap(:INT) { stop! }
91
+ yield if block_given?
92
+ end
93
+
94
+ self
95
+ end
96
+
97
+ # Stops the server if running (ie a handler is set).
98
+ def stop!
99
+ if @handler
100
+ # Use thins' hard #stop! if available, otherwise just #stop
101
+ @handler.respond_to?(:stop!) ? @handler.stop! : @handler.stop
102
+ @handler = nil
103
+
104
+ yield if block_given?
105
+ end
106
+
107
+ self
83
108
  end
84
109
 
85
110
  protected
86
111
 
87
- def lookup_controller(key) # :nodoc:
88
- if development
89
- # unload the controller in development mode so that
90
- # controllers will be reloaded each request
91
-
92
- env.reset
93
- if const = env.seek(:controller, key)
94
- const.unload
95
- const.constantize
96
- else
97
- nil
112
+ # Looks up and returns the first available Rack::Handler as listed in the
113
+ # servers configuration. (Note rack_handler returns a handler class, not
114
+ # an instance). Adapted from Sinatra.detect_rack_handler
115
+ def rack_handler # :nodoc:
116
+ servers.each do |server_name|
117
+ begin
118
+ return Rack::Handler.get(server_name)
119
+ rescue LoadError
120
+ rescue NameError
98
121
  end
99
- else
100
- env[:controller][key]
101
122
  end
123
+ raise "Server handler (#{servers.join(',')}) not found."
102
124
  end
103
125
  end
104
126
  end
@@ -15,7 +15,7 @@ module Tap
15
15
  #config :sym, :sym, &c.symbol # sym
16
16
  config :integer, 10, &c.integer # integer
17
17
  config :numeric, 10, &c.numeric # numeric
18
- config :float, 10, &c.float # float
18
+ config :float, 10.0, &c.float # float
19
19
 
20
20
  config :string_or_nil, nil, &c.string_or_nil # string_or_nil (nil)
21
21
  #config :sym_or_nil, nil, &c.symbol_or_nil # symbol_or_nil (nil)
@@ -0,0 +1,14 @@
1
+ require 'tap/controller'
2
+
3
+ <% redirect do |target| %># :startdoc::controller <replace with summary>
4
+ # <replace with description>
5
+
6
+ # <%= const.name %> Documentation
7
+ class <%= const.name %> < Tap::Controller
8
+
9
+ # Methods define actions on the controller
10
+ def index
11
+ render 'index.erb', :locals => {:obj => 'moon'}, :layout => true
12
+ end
13
+
14
+ end <% module_nest(const.nesting, ' ') { target } end %>
@@ -0,0 +1 @@
1
+ Goodnight <%%= obj %>!
@@ -0,0 +1,57 @@
1
+ <dl>
2
+ <% configurations.each_pair do |key, config| %>
3
+ <% next if config[:type] == :hidden %>
4
+ <% name = "#{name_base}[#{key.inspect}]" %>
5
+ <% value = values[key] %>
6
+
7
+ <% if config.is_nest? %>
8
+ <dt class="name"><%= key %></dt>
9
+ <dd class="nested-configs">
10
+ <%= module_render("configurations.erb", obj, :locals => {
11
+ :name_base => name,
12
+ :configurations => config.default(false).delegates,
13
+ :values => value
14
+ }) %>
15
+ </dd>
16
+ <% next %>
17
+ <% end %>
18
+
19
+ <dt><%= key %></dt>
20
+ <dd>
21
+ <% case config[:type] %>
22
+ <% when :flag %>
23
+ <input name="<%= name %>" type="hidden" value="false" />
24
+ <input name="<%= name %>" type="checkbox" value="true" <%= value ? 'checked="true"' : '' %> />
25
+
26
+ <% when :switch %>
27
+ <input name="<%= name %>" type="radio" value="true" <%= value ? 'checked="true" ' : '' %>>on</input>
28
+ <input name="<%= name %>" type="radio" value="false" <%= !value ? 'checked="true" ' : '' %>>off</input>
29
+
30
+ <% when :select %>
31
+ <select name="<%= name %>">
32
+ <% (config[:options] || []).each do |option| %>
33
+ <option value="<%= option %>" <%= value == option ? "selected='true' " : ""%>><%= option %></option>
34
+ <% end %>
35
+ </select>
36
+
37
+ <% when :list_select %>
38
+ <input type="hidden" name="<%= name %>[]" value="#" />
39
+ <select name="<%= name %>[]" multiple="true">
40
+ <% (config[:options] || []).each do |option| %>
41
+ <option value="<%= option %>" <%= value && value.include?(option) ? "selected='true' " : ""%>><%= option %></option>
42
+ <% end %>
43
+ </select>
44
+
45
+ <% when :hidden %>
46
+ <% next %>
47
+ <% else %>
48
+ <%= render(
49
+ :file => module_path("#{config[:type]}.erb", obj.class) || template_path("configurable/default.erb"),
50
+ :locals => {
51
+ :name => name,
52
+ :config => config,
53
+ :value => value}) %>
54
+ <% end %>
55
+ </dd>
56
+ <% end %>
57
+ </dl>
@@ -0,0 +1 @@
1
+ <input name="<%= name %>" type="text" value="<%= value %>" />
@@ -2,10 +2,13 @@
2
2
  <head>
3
3
  <title>Tap (Server)</title>
4
4
  <link rel="stylesheet" type="text/css" href="/stylesheets/tap.css" />
5
- <script src="/javascripts/prototype.js"></script>
6
- <script src="/javascripts/tap.js"></script>
5
+ <!-- <script src="/javascripts/tap.js"></script> -->
7
6
  </head>
8
7
  <body>
9
8
  <%= content %>
9
+
10
+ <ul>
11
+ <li><a href="/">Home</a></li>
12
+ </ul>
10
13
  </body>
11
14
  </html>
@@ -2,16 +2,18 @@
2
2
 
3
3
  <ul>
4
4
  <li class="source_file">
5
- <h2>Source File</h2>
6
- <p><%= obj.source_file %><p>
5
+ <h2>Registered As</h2>
6
+ <ul><% Lazydoc::Document[obj.to_s].each_pair do |type, comment| %>
7
+ <li><%= type %> (<%= comment.document.source_file %>)</li><% end %>
8
+ </ul>
7
9
  </li>
8
10
  <li>
9
11
  <h2>Summary</h2>
10
- <%= obj.desc.subject %>
12
+ <%= obj.desc ? obj.desc.subject : nil %>
11
13
  </li>
12
14
  <li>
13
15
  <h2>Documentation</h2>
14
- <pre class="desc"><%= obj.desc.wrap %></pre>
16
+ <pre class="desc"><%= obj.desc ? obj.desc.wrap : nil %></pre>
15
17
  </li>
16
18
  <li>
17
19
  <h2>Signature</h2>