wire-framework 0.1.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.
data/lib/app/file.rb ADDED
@@ -0,0 +1,81 @@
1
+ require 'awesome_print'
2
+ require_relative '../wire'
3
+
4
+ # Static is a Wire::App for serving read-only, static files
5
+ # @author Bryan T. Meyers
6
+ module Static
7
+ extend Wire::App
8
+ extend Wire::Resource
9
+
10
+ # Map a file folder to a sub-URI
11
+ # @param [String] resource the sub-URI
12
+ # @param [Class] path the file folder
13
+ # @return [void]
14
+ def self.local(resource, path)
15
+ $current_app[:resources][resource] = { local: path }
16
+ end
17
+
18
+ # Get a file listing for this folder
19
+ # @param [Hash] context the context for this request
20
+ # @return [Response] a listing, or status code
21
+ def self.do_read_all(context)
22
+ path = context.resource[:local]
23
+ if path
24
+ return 404 unless File.exists?(path)
25
+ if File.directory? path
26
+ Dir.entries(path).sort.to_s
27
+ else
28
+ 401
29
+ end
30
+ else
31
+ 404
32
+ end
33
+ end
34
+
35
+ # Get a file from this folder
36
+ # @param [Hash] context the context for this request
37
+ # @return [Response] a file, listing, or status code
38
+ def self.do_read(context)
39
+ path = context.resource[:local]
40
+ id = context.uri[3..context.uri.length].join('/')
41
+ if path
42
+ ext_path = File.join(path, id)
43
+ return 404 unless File.exists?(ext_path)
44
+ if File.directory?(ext_path)
45
+ "#{ap Dir.entries(ext_path).sort}"
46
+ else
47
+ if ext_path.end_with?('.wiki') || ext_path.end_with?('.mediawiki')
48
+ mime = 'text/wiki'
49
+ else
50
+ mime = `mimetype --brief #{ext_path}`
51
+ end
52
+ headers = {}
53
+ headers['Content-Type'] = mime
54
+ headers['Cache-Control'] = 'public'
55
+ headers['Expires'] = "#{(Time.now + 30000000).utc}"
56
+ body = File.read(ext_path)
57
+ [200, headers, body]
58
+ end
59
+ else
60
+ 404
61
+ end
62
+ end
63
+
64
+ # Proxy method used when routing
65
+ # @param [Array] actions the allowed actions for this URI
66
+ # @param [Hash] context the context for this request
67
+ # @return [Response] a Rack Response triplet, or status code
68
+ def self.invoke(actions, context)
69
+ return 404 unless context.resource
70
+ case context.action
71
+ when :read
72
+ if context.uri[3]
73
+ do_read(context)
74
+ else
75
+ do_read_all(context)
76
+ end
77
+ else
78
+ 403
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,59 @@
1
+ require 'awesome_print'
2
+ require 'tilt'
3
+ require_relative '../wire'
4
+ require_relative 'history/svn'
5
+
6
+ # History is a Wire::App for accessing the history of versioned content
7
+ # @author Bryan T. Meyers
8
+ module History
9
+
10
+ # Select the location of the repositories
11
+ # @param [Symbol] path location of the repositories
12
+ # @return [void]
13
+ def repos(path)
14
+ $current_app[:repos_path] = path
15
+ end
16
+
17
+ # Select the render template for histories
18
+ # @param [Symbol] path location of the Tilt compatible template
19
+ # @return [void]
20
+ def log(path)
21
+ $current_app[:template] = Tilt.new(path, 1, { ugly: true })
22
+ end
23
+
24
+ # Select the sub-directory for web-serveable content
25
+ # @param [Symbol] path the sub-directory path
26
+ # @return [void]
27
+ def web_folder(path)
28
+ $current_app[:web] = path
29
+ end
30
+
31
+ # Get the history of a single file or directory
32
+ # @param [Hash] context the context for this request
33
+ # @return [Response] the history, or status code
34
+ def do_read(actions, context)
35
+ resource = context.uri[2]
36
+ web = context.app[:web]
37
+ id = context.uri[3...context.uri.length].join('/')
38
+ list = get_log(web, resource, id)
39
+ if list == 404
40
+ return 404
41
+ end
42
+ template = context.app[:template]
43
+ template.render(self, actions: actions, context: context, list: list)
44
+ end
45
+
46
+ # Proxy method used when routing
47
+ # @param [Array] actions the allowed actions for this URI
48
+ # @param [Hash] context the context for this request
49
+ # @return [Response] a Rack Response triplet, or status code
50
+ def invoke(actions, context)
51
+ return 404 unless context.uri[2]
52
+ case context.action
53
+ when :read
54
+ do_read(actions, context)
55
+ else
56
+ 403
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,34 @@
1
+ require_relative '../repo'
2
+ require 'cobravsmongoose'
3
+
4
+ module History
5
+ # History::SVN is a connector for viewing log information in SVN
6
+ # @author Bryan T. Meyers
7
+ module SVN
8
+ extend Wire::App
9
+ extend Wire::Resource
10
+ extend History
11
+
12
+ # Get the log information for any part of a Repo
13
+ # @param [String] web the web path of the repo
14
+ # @param [String] repo the name of the repository to access
15
+ # @param [String] id the sub-URI of the item to access
16
+ # @return [Hash] the history entries
17
+ def self.get_log(web, repo, id = nil)
18
+ if id.nil?
19
+ log = `svn log -v --xml 'svn://localhost/#{repo}'`
20
+ else
21
+ if web.nil?
22
+ log = `svn log -v --xml 'svn://localhost/#{repo}/#{id}'`
23
+ else
24
+ log = `svn log -v --xml 'svn://localhost/#{repo}/#{web}/#{id}'`
25
+ end
26
+ end
27
+ unless $?.exitstatus == 0
28
+ return 404
29
+ end
30
+ log = CobraVsMongoose.xml_to_hash(log)
31
+ log['log']['logentry']
32
+ end
33
+ end
34
+ end
data/lib/app/login.rb ADDED
@@ -0,0 +1,14 @@
1
+ # Login is a Wire::App for forcing user logins
2
+ # @author Bryan T. Meyers
3
+ module Login
4
+
5
+ # Proxy method used when routing
6
+ # @param [Array] actions the allowed actions for this URI
7
+ # @param [Hash] context the context for this request
8
+ # @return [Response] a redirect message returning to the previous page
9
+ def self.invoke(actions, context)
10
+ referer = context.referer
11
+ [301, { 'Location' => referer }, ['Login Redirect']]
12
+ end
13
+
14
+ end
data/lib/app/render.rb ADDED
@@ -0,0 +1,121 @@
1
+ require 'nokogiri'
2
+ require 'rest-client'
3
+ require 'awesome_print'
4
+ require 'docile'
5
+ require 'tilt'
6
+ require 'json'
7
+ require_relative '../wire'
8
+ require_relative 'render/document'
9
+ require_relative 'render/editor'
10
+ require_relative 'render/instant'
11
+ require_relative 'render/page'
12
+ require_relative 'render/partial'
13
+ require_relative 'render/style'
14
+
15
+ # Render is an Abstract Wire::App for transforming content
16
+ # @author Bryan T. Meyers
17
+ module Render
18
+ include Wire::Resource
19
+
20
+ # Setup the remote connection for content
21
+ # @param [String] hostname http hostname and port of remote
22
+ # @param [String] uri the base URI for content on the remote
23
+ # @return [void]
24
+ def remote(hostname, uri)
25
+ $current_app[:remote_host] = hostname
26
+ $current_app[:remote_uri] = uri
27
+ end
28
+
29
+ # Setup the template for rendering
30
+ # @param [String] path location of the template
31
+ # @param [Proc] block block to execute for setting up template
32
+ # @return [void]
33
+ def template(path, &block)
34
+ $current_app[:template] = { path: path.nil? ? nil : Tilt.new(path, 1, { ugly: true }), sources: {} }
35
+ if block
36
+ Docile.dsl_eval(self, &block)
37
+ end
38
+ end
39
+
40
+ # Enable the use of an outer layout, for the current template
41
+ def use_layout
42
+ $current_app[:template][:use_layout] = true
43
+ end
44
+
45
+ # Setup the source for additional template information
46
+ # @param [Symbol] key the type of key for this source
47
+ # @param [String] uri the path for a remote source
48
+ # @param [Proc] block block to execute for setting up source
49
+ # @return [void]
50
+ def source(key, uri, &block)
51
+ $current_app[:template][:sources][key] = { uri: uri, key: nil }
52
+ $current_source = $current_app[:template][:sources][key]
53
+ if block
54
+ Docile.dsl_eval(self, &block)
55
+ end
56
+ end
57
+
58
+ # Setup the key for additional source information
59
+ # @param [Symbol] type the type of key for this source
60
+ # @return [void]
61
+ def key(type)
62
+ $current_source[:key] = type
63
+ end
64
+
65
+ # Setup the template for rendering single items
66
+ # @param [String] template the path to the template
67
+ # @return [void]
68
+ def single(template)
69
+ partial = Tilt.new(template, 1, { ugly: true })
70
+ $current_resource[:single] = partial
71
+ end
72
+
73
+ # Setup the template for rendering multiple items
74
+ # @param [String] template the path to the template
75
+ # @return [void]
76
+ def multiple(template)
77
+ partial = Tilt.new(template, 1, { ugly: true })
78
+ $current_resource[:multiple] = partial
79
+ end
80
+
81
+ # Setup the template for rendering one or more items
82
+ # @param [String] template the path to the template
83
+ # @return [void]
84
+ def all(template)
85
+ multiple(template)
86
+ single(template)
87
+ end
88
+
89
+ # Proxy method used when forwarding requests
90
+ # @param [Symbol] method the action to use when forwarding
91
+ # @param [Hash] context the context for this request
92
+ # @return [Response] a Rack Response triplet, or status code
93
+ def forward(method, context)
94
+ host = context.app[:remote_host]
95
+ path = context.app[:remote_uri]
96
+ resource = context.uri[2]
97
+ referer = context.referer.join('/')
98
+
99
+ q = '?' + context.query_string
100
+ id = context.uri[3...context.uri.length].join('/')
101
+ case (method)
102
+ when :create
103
+ puts "POST: Forward Request to https://#{host}/#{path}/#{resource}#{q}"
104
+ RestClient.post "http://#{host}/#{path}/#{resource}#{q}", context.body
105
+ when :update
106
+ puts "PUT: Forward Request to https://#{host}/#{path}/#{resource}/#{id}#{q}"
107
+ RestClient.put "http://#{host}/#{path}/#{resource}/#{id}#{q}", context.body
108
+ when :readAll
109
+ puts "GET: Forward Request to https://#{host}/#{path}/#{resource}#{q}"
110
+ RestClient.get "http://#{host}/#{path}/#{resource}#{q}", referer: referer
111
+ when :read
112
+ puts "GET: Forward Request to https://#{host}/#{path}/#{resource}/#{id}#{q}"
113
+ RestClient.get "http://#{host}/#{path}/#{resource}/#{id}#{q}", referer: referer
114
+ when :delete
115
+ puts "DELETE: Forward Request to https://#{host}/#{path}/#{resource}/#{id}#{q}"
116
+ RestClient.delete "http://#{host}/#{path}/#{resource}/#{id}#{q}"
117
+ else
118
+ 401
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,51 @@
1
+ require_relative '../render'
2
+
3
+ module Render
4
+ # Document renders a file to an HTML representation
5
+ # @author Bryan T. Meyers
6
+ module Document
7
+ extend Render
8
+
9
+ # Renders a document or listing to HTML
10
+ # @param [Array] actions the actions allowed for this URI
11
+ # @param [Wire::Context] context the context for this request
12
+ # @param [Symbol] specific the type of read to perform
13
+ # @return [Response] a Rack Response triplet, or status code
14
+ def self.do_read(actions, context, specific)
15
+ begin
16
+ response = forward(specific, context)
17
+ mime = response.headers[:content_type]
18
+ renderer = $renderers[mime]
19
+ if renderer
20
+ template = $templates[renderer]
21
+ template.render(self, { actions: actions, context: context, mime: mime, response: response.body })
22
+ else
23
+ response
24
+ end
25
+ rescue RestClient::ResourceNotFound
26
+ [404, {}, $apps[404][:template][:path].render(self, locals = { actions: actions, context: context })]
27
+ end
28
+ end
29
+
30
+ # Proxy method used when routing
31
+ # @param [Array] actions the allowed actions for this URI
32
+ # @param [Hash] context the context for this request
33
+ # @return [Response] a Rack Response triplet, or status code
34
+ def self.invoke(actions, context)
35
+ case context.action
36
+ when :create
37
+ forward(:create, context)
38
+ when :read
39
+ if context.uri[3]
40
+ do_read(actions, context, :read)
41
+ else
42
+ do_read(actions, context, :readAll)
43
+ end
44
+ when :update
45
+ forward(:update, context)
46
+ else
47
+ 405
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,55 @@
1
+ require_relative '../render'
2
+
3
+ module Render
4
+
5
+ # Editor allows a document to be displayed in an editing form
6
+ # @author Bryan T. Meyers
7
+ module Editor
8
+ extend Render
9
+
10
+ # Open an editor for a document
11
+ # @param [Array] actions the allowed actions for this URI
12
+ # @param [Hash] context the context for this request
13
+ # @return [Response] the Editor with containing document, or status code
14
+ def self.do_read(actions, context)
15
+ resource = context.uri[2]
16
+ query = context.query
17
+ id = context.uri[3...context.uri.length].join('/')
18
+ body = ''
19
+ begin
20
+ response = forward(:read, context)
21
+ mime = response.headers[:content_type]
22
+ body = response.body
23
+ rescue RestClient::ResourceNotFound
24
+ if query[:type]
25
+ mime = query[:type]
26
+ else
27
+ return [404, {}, 'EDITOR: Document type not set for new document']
28
+ end
29
+ end
30
+ template = $editors[mime]
31
+ if template
32
+ template.render(self, { actions: actions, resource: resource, id: id, mime: mime, response: body })
33
+ else
34
+ body
35
+ end
36
+ end
37
+
38
+ # Proxy method used when routing
39
+ # @param [Array] actions the allowed actions for this URI
40
+ # @param [Hash] context the context for this request
41
+ # @return [Response] a Rack Response triplet, or status code
42
+ def self.invoke(actions, context)
43
+ case context.action
44
+ when :create
45
+ forward(:create, context)
46
+ when :read
47
+ do_read(actions, context)
48
+ when :update
49
+ forward(:update, context)
50
+ else
51
+ 405
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,65 @@
1
+ require_relative '../render'
2
+
3
+ module Render
4
+ # Instant allows for previews of edited documents
5
+ # @author Bryan T. Meyers
6
+ module Instant
7
+ extend Render
8
+
9
+ # Render a temporary document to HTML
10
+ # @param [Array] actions the allowed actions for this URI
11
+ # @param [Hash] context the context for this request
12
+ # @return [Response] a Rack Response triplet, or status code
13
+ def self.do_update(actions, context)
14
+ body = context.body
15
+ if body
16
+ body = body.split('=')[1]
17
+ if body
18
+ body = URI.decode(body)
19
+ end
20
+ end
21
+ resource = context.uri[2]
22
+ id = context.uri[3]
23
+ ## Default to not found
24
+ message = ''
25
+ status = 404
26
+ if resource
27
+ if body
28
+ ## Assume unsupported mime type
29
+ status = 415
30
+ message = 'INSTANT: Unsupported MIME Type'
31
+ renderer = $renderers["#{resource}/#{id}"]
32
+ if renderer
33
+ template = $templates[renderer]
34
+ result = template.render(self,
35
+ { actions: actions,
36
+ context: context,
37
+ mime: "#{resource}/#{id}",
38
+ response: body,
39
+ })
40
+ template = context.app[:template]
41
+ if template
42
+ message = template[:path].render(self, { actions: actions, context: context, content: result })
43
+ else
44
+ message = result
45
+ end
46
+ status = 200
47
+ end
48
+ end
49
+ end
50
+ [status, {}, message]
51
+ end
52
+
53
+ # Proxy method used when routing
54
+ # @param [Array] actions the allowed actions for this URI
55
+ # @param [Hash] context the context for this request
56
+ # @return [Response] a Rack Response triplet, or status code
57
+ def self.invoke(actions, context)
58
+ if context.action.eql? :update
59
+ do_update(actions, context)
60
+ else
61
+ 405
62
+ end
63
+ end
64
+ end
65
+ end