vae 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NzZhNTk3MTc0OTgyZDcwMDU1NDRiY2QxNTAxNzUwMTUwMjljODgzYQ==
5
+ data.tar.gz: !binary |-
6
+ Mzg1MTNhZDJhZTBhNGY0ZTU2NjQ5NzVkNjc1YjI5ODE3ZTk5M2NmMQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ MjQ5YTY0MTQ2MTc4MmU2NDgxYmVlNjBhZGU2MThjZWUxMmRjYmQ5NjEyMmM4
10
+ MTM4OTEyZDQzMTYyNjM5ZmY3NDZmZTM1MzEzMGJiZDZiYTVlZjE3YTgwYzgx
11
+ YjQxYzNjOTBkN2UwOGJjODkzYTc1ZmYzY2JhZGY2YjhhNmM2ZTE=
12
+ data.tar.gz: !binary |-
13
+ MjY0ZGYxZDY0NTA0NjQxMTdjZWYwNDFiOWM0ZjVmZDA3Yjg2MDQzNGM2ZjA3
14
+ NDVkN2Y3MzY2MzljODYxZDI0MjE4ZDRiMTA3YWM0MDBkMzdiMjg3ODA2YWQ5
15
+ ZmIyNDgzMDFhOWY1NDNiYTE0MDRlMTk2MTQ4ZTkzOGRiYzBlMmU=
data/bin/vae ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby -W0
2
+
3
+ THIS_FILE = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
4
+ $:.unshift File.dirname(THIS_FILE) + '/../lib'
5
+
6
+ require 'vae'
7
+
8
+ VaeLocal.run_trapping_exceptions!
data/lib/logging.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'logger'
2
+
3
+ module Logging
4
+ def self.logger
5
+ @logger ||= new_logger
6
+ end
7
+
8
+ private
9
+
10
+ def self.new_logger
11
+ logger = Logger.new(STDOUT)
12
+ logger.level = Logger::Severity::WARN
13
+ logger
14
+ end
15
+ end
data/lib/servlet.rb ADDED
@@ -0,0 +1,13 @@
1
+ class Servlet < Mongrel::HttpHandler
2
+
3
+ def process(request, response)
4
+ response.start do |head,out|
5
+ head["Content-Type"] = "text/html"
6
+ out << "Servlet"
7
+ end
8
+ end
9
+
10
+ end
11
+
12
+ class FileNotFound < ArgumentError
13
+ end
data/lib/site.rb ADDED
@@ -0,0 +1,35 @@
1
+ class Site
2
+ attr_accessor :password, :root, :session_id, :subdomain, :username
3
+
4
+ def fetch_from_server(req)
5
+ http = Net::HTTP.new("#{subdomain}.vaesite.com")
6
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
7
+ http.start { |http|
8
+ http.read_timeout = 120
9
+ http.request(req)
10
+ }
11
+ end
12
+
13
+ def initialize(options)
14
+ @root = options[:root] if options[:root]
15
+ @subdomain = options[:subdomain] if options[:subdomain]
16
+ @username = options[:username] if options[:username]
17
+ @password = options[:password] if options[:password]
18
+ @session_id = Digest::MD5.hexdigest(rand.to_s)
19
+ login_to_server
20
+ end
21
+
22
+ def login_to_server
23
+ req = Net::HTTP::Post.new("/?__vae_local=#{session_id}")
24
+ req.body = "__local_username=#{CGI.escape(username)}&__local_password=#{CGI.escape(password)}&__local_version=#{VER}"
25
+ res = fetch_from_server(req)
26
+ if res.body == "BAD"
27
+ raise VaeError, "Invalid password or insufficient permissions."
28
+ elsif res.body =~ /MSG/
29
+ puts res.body.gsub(/MSG/, "")
30
+ elsif res.body != "GOOD"
31
+ raise VaeError, "Could not connect to Vae servers. Please check your Internet connection."
32
+ end
33
+ end
34
+
35
+ end
data/lib/vae.rb ADDED
@@ -0,0 +1,180 @@
1
+ require 'rubygems'
2
+
3
+ require 'cgi'
4
+ require 'digest/md5'
5
+ require 'mongrel'
6
+ require 'net/http'
7
+ require 'net/https'
8
+ require 'optparse'
9
+ require 'thread'
10
+ require 'webrick'
11
+ require 'yaml'
12
+
13
+ require 'directory_watcher'
14
+ require 'highline/import'
15
+ require 'compass'
16
+ require 'haml'
17
+
18
+ require 'logging'
19
+ require 'servlet'
20
+ require 'site'
21
+ require 'vae_error'
22
+ require 'vae_site_servlet'
23
+ require 'vae_local_servlet'
24
+ require 'version'
25
+
26
+ SERVER_PARSED = [ ".html", ".haml", ".php", ".xml", ".rss", ".pdf.haml", ".pdf.haml.php", ".haml.php" ]
27
+ SERVER_PARSED_GLOB = [ "**/*.html", "**/*.haml", "**/*.php", "**/*.xml", "**/*.rss", "**/*.pdf.haml", "**/*.pdf.haml.php", "**/*.haml.php" ]
28
+ BANNER = "Vae local preview server, version #{VER}"
29
+
30
+ class VaeLocal
31
+
32
+ def fetch_from_vaeplatform(site, req)
33
+ http = Net::HTTP.new("#{site}.vaeplatform.com", 443)
34
+ http.use_ssl = true
35
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
36
+ http.start { |http|
37
+ http.read_timeout = 120
38
+ http.request(req)
39
+ }
40
+ end
41
+
42
+ def get_svn_credentials(site)
43
+ home = Dir.chdir { Dir.pwd }
44
+ Dir.glob("#{home}/.subversion/auth/svn.simple/*").each do |file|
45
+ params = parse_svn_auth_file(file)
46
+ if params["svn:realmstring"] =~ /<http:\/\/svn(\.|_)#{site}.(vae|verb)site.com/ or params["svn:realmstring"] =~ /<http:\/\/#{site}(\.|_)svn.(vae|verb)site.com/
47
+ return params
48
+ end
49
+ end
50
+ {}
51
+ end
52
+
53
+ def parse_svn_auth_file(file)
54
+ key = nil
55
+ mode = nil
56
+ params = {}
57
+ File.read(file).each_line do |line|
58
+ line.strip!
59
+ if mode == :key
60
+ key = line
61
+ mode = nil
62
+ elsif mode == :value
63
+ params[key] = line
64
+ mode = nil
65
+ else
66
+ if line[0,1] == "K"
67
+ mode = :key
68
+ elsif line[0, 1] == "V"
69
+ mode = :value
70
+ end
71
+ end
72
+ end
73
+ params
74
+ end
75
+
76
+ def run!
77
+ options = { :port => 9999 }
78
+ ARGV.options do |opts|
79
+ opts.banner = BANNER + "\n\nUsage: vae [options]\n starts a local development server\n vae [options] deploy\n promotes the source in Subversion repository to the FTP\n\n If you are using the Vae Production environment features:\n vae [options] stage\n promotes the source in Subversion repository to the staging environment\n vae [options] stagerelease\n promotes the source in Subversion repository to the staging environment\n and releases it to the production environment\n vae [options] release\n releases the current staging environment to the production environment\n vae [options] rollback\n rolls back the production environment to a previous release\n\nAvailable Options:"
80
+ opts.on("-u","--username <username>","Your Vae username") { |o| options[:username] = o }
81
+ opts.on("-p","--port <port number>","Start server on this port") { |o| options[:port] = o }
82
+ opts.on("-r","--root <path to site root>","Path to the root of the local copy of your Vae site.") { |o| options[:site_root] = o }
83
+ opts.on("-s","--site <subdomain>","Vae subdomain for this site") { |o| options[:site] = o }
84
+ opts.on_tail("-h","--help", "Show this help message") { puts opts; exit }
85
+ opts.parse!
86
+ end
87
+ options[:site_root] = Dir.pwd if options[:site_root].nil? and (File.exists?("#{Dir.pwd}/__vae.yml") or File.exists?("#{Dir.pwd}/__verb.yml"))
88
+ if options[:site_root]
89
+ [ "verb", "vae" ].each do |name|
90
+ if File.exists?("#{options[:site_root]}/__#{name}.yml")
91
+ site_conf_file = File.read("#{options[:site_root]}/__#{name}.yml")
92
+ site_conf = YAML.load(site_conf_file)
93
+ options[:site] = site_conf[name]["site"] if site_conf[name] and site_conf[name]["site"]
94
+ end
95
+ end
96
+ end
97
+ raise VaeError, "We could not determine the Vae subdomain for this site. Please specify it manually by using the --site option or create a __vae.yml file within the site root." if options[:site].nil?
98
+ unless options[:username]
99
+ svn_credentials = get_svn_credentials(options[:site])
100
+ options[:username] = svn_credentials["username"]
101
+ options[:password] = svn_credentials["password"]
102
+ end
103
+ raise VaeError, "We could not determine the Vae username that you use. Please specify it manually by using the --username option." if options[:username].nil?
104
+ if options[:password].nil?
105
+ options[:password] = ask("Please enter the Vae password for username #{options[:username]}:") {|q| q.echo = false}
106
+ end
107
+ if [ "deploy", "release", "rollback", "stage", "stagerelease" ].include?(ARGV.last)
108
+ stagerelease(ARGV.last, options[:site], options[:username], options[:password])
109
+ exit
110
+ end
111
+ raise VaeError, "You did not specify the path to the root of the local copy of your Vae site. Please specify it manually by using the --root option or cd to the site root (and make sure it contains a __vae.yml file)." unless options[:site_root]
112
+ raise VaeError, "You specified an invalid path to the local copy of your Vae site." unless File.exists?(options[:site_root])
113
+
114
+ $biglock = Mutex.new
115
+ dw = DirectoryWatcher.new options[:site_root], :interval => 1.0, :glob => SERVER_PARSED_GLOB, :pre_load => true
116
+ dw.add_observer { |*args|
117
+ args.each { |event|
118
+ path = event.path.gsub($site.root, "")
119
+ $biglock.synchronize {
120
+ $changed[path] = event.type
121
+ }
122
+ }
123
+ }
124
+ dw.start
125
+
126
+ Dir.chdir File.dirname(__FILE__)
127
+ puts BANNER
128
+ puts "Vae is in action at http://localhost:#{options[:port]}/"
129
+ puts " (hit Control+C to exit)"
130
+ $site = Site.new(:subdomain => options[:site], :root => options[:site_root], :username => options[:username], :password => options[:password])
131
+ $cache = {}
132
+ $changed = {}
133
+ $server = Mongrel::Configurator.new :host => "0.0.0.0", :port => options[:port] do
134
+ listener do
135
+ uri "/", :handler => VaeSiteServlet.new
136
+ #uri "/__welcome/", :handler => VaeLocalServlet.new
137
+ end
138
+ trap("INT") { raise Mongrel::StopServer }
139
+ run
140
+ end
141
+
142
+ begin
143
+ $server.join
144
+ rescue Mongrel::StopServer
145
+ puts "Thanks for using Vae!"
146
+ end
147
+ end
148
+
149
+ def stagerelease(action, site, username, password)
150
+ if action == "deploy"
151
+ action = "stage"
152
+ elsif action == "stagerelease"
153
+ stagerelease("stage", site, username, password)
154
+ stagerelease("release", site, username, password)
155
+ return
156
+ end
157
+ req = Net::HTTP::Post.new("/subversion/#{action}")
158
+ req.body = "username=#{CGI.escape(username)}&password=#{CGI.escape(password)}"
159
+ res = fetch_from_vaeplatform(site, req)
160
+ if res.is_a?(Net::HTTPFound)
161
+ raise VaeError, "Invalid username/password or insufficient permissions."
162
+ else
163
+ puts res.body
164
+ end
165
+ end
166
+
167
+ def self.run_trapping_exceptions!
168
+ begin
169
+ v = VaeLocal.new
170
+ v.run!
171
+ rescue VaeError => e
172
+ cmd = $0
173
+ cmd = "vae" if cmd =~ /\.\.\/vae_local/
174
+ puts "** Error:"
175
+ puts " " + e.to_s
176
+ puts "Type #{cmd} --help for help."
177
+ end
178
+ end
179
+
180
+ end
data/lib/vae_error.rb ADDED
@@ -0,0 +1,2 @@
1
+ class VaeError < StandardError
2
+ end
@@ -0,0 +1,3 @@
1
+ class VaeLocalServlet < Servlet
2
+ end
3
+
@@ -0,0 +1,185 @@
1
+ class VaeSiteServlet < Servlet
2
+
3
+ def bundle_changed_source_files(source_files)
4
+ source_files ||= []
5
+ changed = nil
6
+ $biglock.synchronize {
7
+ changed = $changed
8
+ $changed = {}
9
+ }
10
+ source_files.concat(changed.map { |filename,action|
11
+ get_source_file(filename, (action == :deleted))
12
+ }).reject { |src| src.nil? }
13
+ end
14
+
15
+ def get_source_file(path, optional = false)
16
+ full_path = nil
17
+ if File.exists?($site.root + path)
18
+ full_path = path
19
+ else
20
+ SERVER_PARSED.each do |ext|
21
+ if full_path.nil? and File.exists?($site.root + path + ext)
22
+ full_path = path + ext
23
+ end
24
+ end
25
+ end
26
+ if full_path.nil? and !optional
27
+ raise FileNotFound
28
+ elsif full_path
29
+ begin
30
+ file = File.read($site.root + full_path)
31
+ md5 = Digest::MD5.hexdigest(file)
32
+ rescue Errno::EISDIR
33
+ return nil
34
+ end
35
+ else
36
+ full_path = path
37
+ md5 = ""
38
+ file = ""
39
+ end
40
+ if $cache[full_path] != md5
41
+ $cache[full_path] = md5
42
+ [ full_path, file ]
43
+ else
44
+ nil
45
+ end
46
+ end
47
+
48
+ def fetch_from_vae(wb_req, method, source_files = nil)
49
+ uri = wb_req.params["REQUEST_URI"] + ((wb_req.params["REQUEST_URI"] =~ /\?/) ? "&" : "?") + "__vae_local=#{$site.session_id}"
50
+ source_files = bundle_changed_source_files(source_files)
51
+ if method == "GET"
52
+ if source_files.is_a?(Array) and source_files.size > 0
53
+ req = Net::HTTP::Post.new(uri)
54
+ source_files.map { |src| puts "sending #{src[0]}" }
55
+ req.body = source_files.collect { |src| "__vae_local_files[#{src[0]}]=#{CGI.escape(src[1])}" }.join("&")
56
+ else
57
+ req = Net::HTTP::Get.new(uri)
58
+ end
59
+ else
60
+ if source_files.is_a?(Array) and source_files.size > 0
61
+ fetch_from_vae(wb_req, "GET", source_files)
62
+ end
63
+ req = Net::HTTP::Post.new(uri)
64
+ req.body = wb_req.body.read
65
+ end
66
+ req['cookie'] = wb_req.params["HTTP_COOKIE"]
67
+ if wb_req.params['HTTP_X_REQUESTED_WITH']
68
+ req['X-Requested-With'] = wb_req.params['HTTP_X_REQUESTED_WITH']
69
+ end
70
+ res = $site.fetch_from_server(req)
71
+ if res.body =~ /__vae_local_needs=(.*)/
72
+ begin
73
+ return fetch_from_vae(wb_req, method, [ get_source_file($1) ])
74
+ rescue FileNotFound
75
+ puts "*\n* Could not find #{$1} -- giving up!\n*"
76
+ return $site.fetch_from_server(Net::HTTP::Get.new("/error_pages/not_found.html"))
77
+ end
78
+ end
79
+ res
80
+ end
81
+
82
+ def fetch_from_vae_and_include_source_of_current_page(req, method)
83
+ fetch_from_vae(req, method, [ find_source_file_from_path(req.params["REQUEST_URI"]), get_source_file("/__vae.php", true), get_source_file("/__verb.php", true) ])
84
+ end
85
+
86
+ def find_source_file_from_path(path)
87
+ path_parts = path.split("/").reject { |part| part.length < 1 }
88
+ local_path = ""
89
+ loop do
90
+ gotit = false
91
+ if part = path_parts.shift
92
+ new_local_path = local_path + "/" + part
93
+ (SERVER_PARSED + [ "" ]).each do |ext|
94
+ if File.exists?($site.root + new_local_path + ext)
95
+ gotit = true
96
+ local_path = new_local_path + ext
97
+ end
98
+ end
99
+ end
100
+ break unless gotit
101
+ end
102
+ return nil unless local_path.length > 0
103
+ get_source_file(local_path)
104
+ end
105
+
106
+ def not_modified?(req, res, mtime, etag)
107
+ return true if (ims = req.params['IF_MODIFIED_SINCE']) && Time.parse(ims) >= mtime
108
+ return true if (inm = req.params['IF_NONE_MATCH']) && WEBrick::HTTPUtils::split_header_value(inm).member?(etag)
109
+ false
110
+ end
111
+
112
+ def render_sass(local_path)
113
+ begin
114
+ options = Compass.sass_engine_options
115
+ options[:load_paths] << File.dirname(local_path)
116
+ engine = Sass::Engine.new(open(local_path, "rb").read, options)
117
+ engine.render
118
+ rescue Sass::SyntaxError => e
119
+ e.message
120
+ end
121
+ end
122
+
123
+ def process(request, response)
124
+ serve(request, response)
125
+ response.finished
126
+ end
127
+
128
+ def serve(req, res)
129
+ res.status = 200
130
+ local_path = ($site.root+req.params["REQUEST_URI"] || "/").split("?").first
131
+ if File.exists?(local_path) and !File.directory?(local_path) and !server_parsed?(local_path)
132
+ st = File::stat(local_path)
133
+ mtime = st.mtime
134
+ etag = sprintf("%x-%x-%x", st.ino, st.size, st.mtime.to_i)
135
+ res.header['etag'] = etag
136
+ if not_modified?(req, res, mtime, etag)
137
+ puts "#{req.params["REQUEST_URI"]} not modified"
138
+ res.status = 304
139
+ else
140
+ mtype = WEBrick::HTTPUtils::mime_type(local_path, WEBrick::HTTPUtils::DefaultMimeTypes)
141
+ res.header['last-modified'] = mtime.httpdate
142
+ if req.params["REQUEST_URI"] =~ /.sass$/
143
+ res.header['Content-Type'] = "text/css"
144
+ res.body << render_sass(local_path)
145
+ else
146
+ res.header['Content-Type'] = mtype
147
+ res.body << open(local_path, "rb").read
148
+ end
149
+ puts "#{req.params["REQUEST_URI"]} local asset"
150
+ end
151
+ else
152
+ if req.params["REQUEST_URI"] =~ /^\/__data\// or req.params["REQUEST_URI"] =~ /^\/__assets\//
153
+ from_vae = { 'location' => "http://#{$site.subdomain}.vaesite.com#{req.params["REQUEST_URI"]}"}
154
+ puts "#{req.params["REQUEST_URI"]} static asset"
155
+ else
156
+ from_vae = fetch_from_vae_and_include_source_of_current_page(req, req.params["REQUEST_METHOD"])
157
+ if from_vae['location']
158
+ puts "#{req.params["REQUEST_URI"]} redirecting to #{from_vae['location']}"
159
+ end
160
+ end
161
+ if from_vae['location']
162
+ res.body << "<p>Redirecting to <a href=\"#{from_vae['location']}\">#{from_vae['location']}</a>"
163
+ res.status = 302
164
+ res.header['Location'] = from_vae['location']
165
+ else
166
+ res.header['Etag'] = from_vae['etag']
167
+ res.header['Last-Modified'] = from_vae['last-modified']
168
+ res.header['Content-Type'] = from_vae['content-type']
169
+ res.header['Content-Disposition'] = from_vae['content-disposition']
170
+ res.header['Set-Cookie'] = from_vae['set-cookie']
171
+ puts "#{req.params["REQUEST_URI"]} rendering"
172
+ res.body << from_vae.body
173
+ end
174
+ end
175
+ end
176
+
177
+ def server_parsed?(path)
178
+ SERVER_PARSED.each do |ext|
179
+ return true if Regexp.new("#{ext}$").match(path)
180
+ end
181
+ false
182
+ end
183
+
184
+ end
185
+
data/lib/version.rb ADDED
@@ -0,0 +1 @@
1
+ VER = "0.6.0"
data/test/vae_test.rb ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.dirname(__FILE__) + '/lib'
4
+ require 'test/unit'
5
+ require 'vae'
6
+
7
+ class VaeTest < Test::Unit::TestCase
8
+
9
+ def setup
10
+ end
11
+
12
+ def test_server_parsed
13
+ servlet = VaeSiteServlet.new({})
14
+ assert servlet.server_parsed?("cow.html")
15
+ assert servlet.server_parsed?("cow.pdf.html")
16
+ assert servlet.server_parsed?("cow.haml")
17
+ assert servlet.server_parsed?("cow.xml")
18
+ assert servlet.server_parsed?("cow.rss")
19
+ assert servlet.server_parsed?("cow.php")
20
+ assert servlet.server_parsed?("cow.haml.php")
21
+ assert !servlet.server_parsed?("cow.sass")
22
+ assert !servlet.server_parsed?("cow.gif")
23
+ assert !servlet.server_parsed?("cow.html.gif")
24
+ assert !servlet.server_parsed?("cow")
25
+ assert !servlet.server_parsed?("cow.haml.php.jpg")
26
+ end
27
+
28
+ end
metadata ADDED
@@ -0,0 +1,168 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vae
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.0
5
+ platform: ruby
6
+ authors:
7
+ - Action Verb, LLC
8
+ - Kevin Bombino
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-09-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: av-redis-client
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '='
19
+ - !ruby/object:Gem::Version
20
+ version: 0.2.2
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '='
26
+ - !ruby/object:Gem::Version
27
+ version: 0.2.2
28
+ - !ruby/object:Gem::Dependency
29
+ name: chunky_png
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ! '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ! '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: compass
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - '='
47
+ - !ruby/object:Gem::Version
48
+ version: 0.11.5
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - '='
54
+ - !ruby/object:Gem::Version
55
+ version: 0.11.5
56
+ - !ruby/object:Gem::Dependency
57
+ name: directory_watcher
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: haml
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - '='
75
+ - !ruby/object:Gem::Version
76
+ version: 3.1.2
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - '='
82
+ - !ruby/object:Gem::Version
83
+ version: 3.1.2
84
+ - !ruby/object:Gem::Dependency
85
+ name: highline
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :runtime
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ! '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: mongrel
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - '='
103
+ - !ruby/object:Gem::Version
104
+ version: 1.2.0.pre2
105
+ type: :runtime
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - '='
110
+ - !ruby/object:Gem::Version
111
+ version: 1.2.0.pre2
112
+ - !ruby/object:Gem::Dependency
113
+ name: sass
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - '='
117
+ - !ruby/object:Gem::Version
118
+ version: 3.1.4
119
+ type: :runtime
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - '='
124
+ - !ruby/object:Gem::Version
125
+ version: 3.1.4
126
+ description: Supports local development for Vae Platform (http://vaeplatform.com/)
127
+ email: support@actionverb.com
128
+ executables:
129
+ - vae
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - bin/vae
134
+ - lib/logging.rb
135
+ - lib/servlet.rb
136
+ - lib/site.rb
137
+ - lib/vae.rb
138
+ - lib/vae_error.rb
139
+ - lib/vae_local_servlet.rb
140
+ - lib/vae_site_servlet.rb
141
+ - lib/version.rb
142
+ - test/vae_test.rb
143
+ homepage: http://vaeplatform.com/vae_local
144
+ licenses:
145
+ - GPL
146
+ metadata: {}
147
+ post_install_message:
148
+ rdoc_options: []
149
+ require_paths:
150
+ - lib
151
+ required_ruby_version: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - ! '>='
154
+ - !ruby/object:Gem::Version
155
+ version: '0'
156
+ required_rubygems_version: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ! '>='
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ requirements: []
162
+ rubyforge_project:
163
+ rubygems_version: 2.0.3
164
+ signing_key:
165
+ specification_version: 4
166
+ summary: This gem allows for local development for sites on Vae Platform (http://vaeplatform.com/)
167
+ test_files: []
168
+ has_rdoc: