true-web 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ .idea
2
+ *.gem
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm 1.9.2-p180@true-web
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ if respond_to? :source
2
+ source :gemcutter
3
+ source "http://gems.github.com"
4
+ end
5
+
6
+ gemspec :name => "true-web"
data/Gemfile.lock ADDED
@@ -0,0 +1,99 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ true-web (0.1.0)
5
+ activesupport (>= 3.0.0)
6
+ honkster-addressable (>= 2.2.3)
7
+ i18n (>= 0.5.0)
8
+ mustache (>= 0.99.2)
9
+ named-routes (>= 0.2.5)
10
+ sinatra (>= 1.2.0)
11
+ yajl-ruby (>= 0.8.1)
12
+
13
+ GEM
14
+ remote: http://rubygems.org/
15
+ remote: http://gems.github.com/
16
+ specs:
17
+ activesupport (3.0.9)
18
+ addressable (2.2.4)
19
+ archive-tar-minitar (0.5.2)
20
+ capybara (0.4.0)
21
+ celerity (>= 0.7.9)
22
+ culerity (>= 0.2.4)
23
+ mime-types (>= 1.16)
24
+ nokogiri (>= 1.3.3)
25
+ rack (>= 1.0.0)
26
+ rack-test (>= 0.5.4)
27
+ selenium-webdriver (>= 0.0.27)
28
+ xpath (~> 0.1.2)
29
+ celerity (0.8.8)
30
+ childprocess (0.1.7)
31
+ ffi (~> 0.6.3)
32
+ columnize (0.3.2)
33
+ crack (0.1.8)
34
+ culerity (0.2.15)
35
+ diff-lcs (1.1.2)
36
+ ffi (0.6.3)
37
+ rake (>= 0.8.7)
38
+ honkster-addressable (2.2.3)
39
+ i18n (0.6.0)
40
+ json_pure (1.5.1)
41
+ linecache19 (0.5.11)
42
+ ruby_core_source (>= 0.1.4)
43
+ mime-types (1.16)
44
+ mustache (0.99.4)
45
+ named-routes (0.2.6)
46
+ activesupport (>= 3.0.0)
47
+ nokogiri (1.4.4)
48
+ rack (1.2.2)
49
+ rack-test (0.5.6)
50
+ rack (>= 1.0)
51
+ rake (0.8.7)
52
+ rr (1.0.2)
53
+ rspec (2.2.0)
54
+ rspec-core (~> 2.2)
55
+ rspec-expectations (~> 2.2)
56
+ rspec-mocks (~> 2.2)
57
+ rspec-core (2.5.1)
58
+ rspec-expectations (2.5.0)
59
+ diff-lcs (~> 1.1.2)
60
+ rspec-mocks (2.5.0)
61
+ ruby-debug-base19 (0.11.24)
62
+ columnize (>= 0.3.1)
63
+ linecache19 (>= 0.5.11)
64
+ ruby_core_source (>= 0.1.4)
65
+ ruby-debug19 (0.11.6)
66
+ columnize (>= 0.3.1)
67
+ linecache19 (>= 0.5.11)
68
+ ruby-debug-base19 (>= 0.11.19)
69
+ ruby_core_source (0.1.4)
70
+ archive-tar-minitar (>= 0.5.2)
71
+ rubyzip (0.9.4)
72
+ selenium-webdriver (0.1.3)
73
+ childprocess (~> 0.1.5)
74
+ ffi (~> 0.6.3)
75
+ json_pure
76
+ rubyzip
77
+ sinatra (1.2.6)
78
+ rack (~> 1.1)
79
+ tilt (>= 1.2.2, < 2.0)
80
+ tilt (1.3.2)
81
+ webmock (1.6.2)
82
+ addressable (>= 2.2.2)
83
+ crack (>= 0.1.7)
84
+ xpath (0.1.3)
85
+ nokogiri (~> 1.3)
86
+ yajl-ruby (0.8.2)
87
+
88
+ PLATFORMS
89
+ ruby
90
+
91
+ DEPENDENCIES
92
+ capybara (>= 0.4.0)
93
+ nokogiri (>= 1.4.4)
94
+ rack-test (>= 0.5.6)
95
+ rr (>= 1.0.2)
96
+ rspec (>= 2.2.0)
97
+ ruby-debug19 (>= 0.11.6)
98
+ true-web!
99
+ webmock (>= 1.6.2)
data/README ADDED
File without changes
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
data/lib/true-web.rb ADDED
@@ -0,0 +1,131 @@
1
+ dir = File.dirname(__FILE__)
2
+ Dir[File.expand_path("#{dir}/../vendor/*/lib")].each do |path|
3
+ $LOAD_PATH.unshift(path)
4
+ end
5
+ require 'nokogiri'
6
+ require 'sinatra/base'
7
+ require 'mustache'
8
+ require 'yajl'
9
+ require 'active_support/all'
10
+ require 'addressable/uri'
11
+ require "named-routes"
12
+ require "superhash"
13
+ require "#{dir}/true-web/version"
14
+ require "#{dir}/true-web/env_methods"
15
+
16
+ module TrueWeb
17
+ def self.included(mod)
18
+ mod.extend(ClassMethods)
19
+ end
20
+
21
+ module ClassMethods
22
+ attr_accessor :controller, :application_name, :named_routes, :stderr_dir, :stdout_dir, :root_dir, :views_class
23
+ alias_method :uris, :named_routes
24
+ delegate :define_routes, :to => :controller
25
+
26
+ include ::TrueWeb::EnvMethods
27
+
28
+ def init(params={})
29
+ self.controller = params[:controller] || raise(ArgumentError, "You must provide an :controller param")
30
+ self.application_name = params[:application_name] || raise(ArgumentError, "You must provide an :application_name param")
31
+ self.root_dir = params[:root_dir] || raise(ArgumentError, "You must provide a :root_dir param")
32
+ self.named_routes = params[:named_routes] || raise(ArgumentError, "You must provide a :named_routes param")
33
+ self.views_class = params[:views_class] || raise(ArgumentError, "You must provide a :views_class param")
34
+ self.controller.config = self
35
+
36
+ plugins.init
37
+ end
38
+
39
+ def app
40
+ @app ||= Rack::Builder.new do
41
+ run controller
42
+ end.to_app
43
+ end
44
+
45
+ def register_service(path, &block)
46
+ unless service_dirs.include?(path)
47
+ service = Service.new(path)
48
+ services << service
49
+ service.init(&block)
50
+ end
51
+ end
52
+
53
+ def service_dirs
54
+ services.map do |service|
55
+ service.root_dir
56
+ end
57
+ end
58
+
59
+ def services
60
+ @services ||= []
61
+ end
62
+
63
+ def services_by_url_prefix
64
+ services.group_by do |service|
65
+ service.url_prefix
66
+ end
67
+ end
68
+
69
+ def services_by_root_dir
70
+ services.inject({}) do |memo, service|
71
+ memo[service.root_dir] = service
72
+ memo
73
+ end
74
+ end
75
+
76
+ def stderr_logger
77
+ @stderr_logger ||= Logger.new(stderr_dir)
78
+ end
79
+
80
+ def stdout_logger
81
+ @stdout_logger ||= Logger.new(stdout_dir)
82
+ end
83
+
84
+ def plugins
85
+ @plugins ||= ::TrueWeb::Plugins::Set.new(self)
86
+ end
87
+
88
+ def lib_dir
89
+ File.join(root_dir, "lib")
90
+ end
91
+
92
+ def stylesheets_dirs
93
+ service_subdirectory_dirs "app/stylesheets"
94
+ end
95
+
96
+ def vendor_dir
97
+ File.join(root_dir, "vendor")
98
+ end
99
+
100
+ def services_dir
101
+ File.join(root_dir, "services")
102
+ end
103
+
104
+ def service_subdirectory_dirs(relative_directory)
105
+ service_dirs.flatten.map do |service_path|
106
+ full_path = File.join(service_path, relative_directory)
107
+ full_path if File.directory?(full_path)
108
+ end.compact
109
+ end
110
+
111
+ def stderr_dir
112
+ "#{root_dir}/log/#{application_name}.#{rack_env}.stderr.log"
113
+ end
114
+
115
+ def stdout_dir
116
+ "#{root_dir}/log/#{application_name}.#{rack_env}.stdout.log"
117
+ end
118
+
119
+ def remove_generated_files
120
+ Dir["#{root_dir}/**/public/**/*.generated"].each do |generated_path|
121
+ FileUtils.rm_f(File.join(File.dirname(generated_path), File.basename(generated_path, ".generated")))
122
+ FileUtils.rm_f(generated_path)
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ require "#{dir}/true-web/controller"
129
+ require "#{dir}/true-web/service"
130
+ require "#{dir}/true-web/views"
131
+ require "#{dir}/true-web/plugins"
@@ -0,0 +1,123 @@
1
+ module TrueWeb
2
+ class Controller < Sinatra::Base
3
+ set :raise_errors, false
4
+ set :show_exceptions, false
5
+
6
+ class_inheritable_accessor :config
7
+ extend(Module.new do
8
+ def uris
9
+ config.uris
10
+ end
11
+
12
+ def views_class
13
+ config.views_class
14
+ end
15
+
16
+ def path(*args, &block)
17
+ uris.path(*args, &block)
18
+ end
19
+
20
+ def services
21
+ config.services
22
+ end
23
+ end)
24
+
25
+ TEMPLATE_TYPE_NAME = "Template"
26
+
27
+ set :logging, true
28
+ set :static, true
29
+ attr_reader :helper, :views
30
+
31
+ error(403) do
32
+ "<div>Sorry, the page you're trying to access is private.</div>"
33
+ end
34
+
35
+ error(404) do
36
+ "<div>Sorry, we could not find the page you were looking for.</div>"
37
+ end
38
+
39
+ error(500) do
40
+ env["rack.exception"] = env["sinatra.error"]
41
+ "<div>Oops, an error occurred.</div>"
42
+ end
43
+
44
+ before do
45
+ @views = self.class.views_class.new(self)
46
+ end
47
+
48
+ def services
49
+ self.class.services
50
+ end
51
+
52
+ def uris
53
+ self.class.uris
54
+ end
55
+
56
+ def view(path, *args)
57
+ views[path].render(*args)
58
+ end
59
+
60
+ def static!
61
+ nil
62
+ end
63
+
64
+ module Controllers
65
+ module ClassMethods
66
+ def define_routes(&route_definition)
67
+ controller = Class.new(self)
68
+ controller.class_eval(&route_definition)
69
+ controllers << controller
70
+ end
71
+
72
+ def controllers
73
+ @controllers ||= []
74
+ end
75
+
76
+ def pagelet_access_resources(pagelet_json_path, paglet_asset_json_path, html_path=nil)
77
+ if html_path
78
+ get html_path do
79
+ send(html_path)
80
+ end
81
+ end
82
+
83
+ get pagelet_json_path do
84
+ response['Content-Type'] = 'application/json'
85
+ send(paglet_asset_json_path).merge(
86
+ html_path ? {
87
+ :html => send(html_path)
88
+ } : {}
89
+ ).to_json
90
+ end
91
+
92
+ get paglet_asset_json_path do
93
+ response['Content-Type'] = 'application/json'
94
+ send(paglet_asset_json_path).to_json
95
+ end
96
+ end
97
+ end
98
+
99
+ def self.included(mod)
100
+ mod.extend(ClassMethods)
101
+ end
102
+
103
+ # Overrode call! to speed up routing to subresources.
104
+ def call!(env)
105
+ self.class.controllers.each do |controller|
106
+ request = ::Sinatra::Request.new(env)
107
+ routes = controller.routes[request.request_method] || []
108
+ path = unescape(request.path_info)
109
+ routes.each do |pattern, keys, conditions, block|
110
+ if pattern.match(path)
111
+ subapp_instance = controller.allocate
112
+ subapp_instance.send(:initialize, nil)
113
+ response = subapp_instance.call(env)
114
+ return response if response[0] != 404
115
+ end
116
+ end
117
+ end
118
+ super
119
+ end
120
+ end
121
+ include Controllers
122
+ end
123
+ end
@@ -0,0 +1,13 @@
1
+ module TrueWeb
2
+ module EnvMethods
3
+ def development?
4
+ rack_env == "development"
5
+ end
6
+
7
+ def rack_env
8
+ ENV["RACK_ENV"]
9
+ end
10
+
11
+ extend self
12
+ end
13
+ end
@@ -0,0 +1,29 @@
1
+ module TrueWeb
2
+ module Plugins
3
+ class Set
4
+ attr_reader :config
5
+ def initialize(config)
6
+ @config = config
7
+ end
8
+
9
+ def on_init(&block)
10
+ @on_init ||= []
11
+ if block
12
+ @on_init.push(block)
13
+ else
14
+ @on_init
15
+ end
16
+ end
17
+
18
+ def init
19
+ self.on_init.each do |block|
20
+ block.call(config)
21
+ end
22
+ end
23
+ end
24
+
25
+ Dir["#{File.dirname(__FILE__)}/plugins/*.rb"].each do |file|
26
+ require file
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,14 @@
1
+ module TrueWeb
2
+ module Plugins
3
+ module DirectoryFirstSort
4
+ def directory_first_sort
5
+ lambda do |path|
6
+ dir = File.dirname(path)
7
+ [dir.length, dir, File.basename(path)]
8
+ end
9
+ end
10
+
11
+ extend self
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,176 @@
1
+ module TrueWeb
2
+ class Service
3
+ attr_reader :root_dir
4
+ attr_accessor :url_prefix
5
+
6
+ def initialize(dir)
7
+ @root_dir = dir
8
+ end
9
+
10
+ def init
11
+ init_controllers
12
+ autoload_models
13
+ append_load_paths
14
+ eval_init_rb
15
+ yield(self) if block_given?
16
+ self
17
+ end
18
+
19
+ def append_load_paths
20
+ lib_dir = File.join(root_dir, "lib")
21
+ $LOAD_PATH << lib_dir if File.directory?(lib_dir)
22
+ end
23
+
24
+ def get_presenter_file_path(url)
25
+ stripped_url_prefix = strip_url_prefix(url)
26
+ file_path = File.join(presenters_dir, "#{stripped_url_prefix}.rb")
27
+ File.file?(file_path) ? file_path : nil
28
+ end
29
+
30
+ def get_stylesheet_file_path(url)
31
+ stripped_url_prefix = strip_url_prefix(url)
32
+ file_path = File.join(app_dir, stripped_url_prefix.gsub(/\.css$/, ".sass"))
33
+ File.file?(file_path) ? file_path : nil
34
+ end
35
+
36
+ def get_static_file_path(url)
37
+ stripped_url_prefix = strip_url_prefix(url)
38
+ static_file_dirs.each do |dir|
39
+ file_path = File.join(dir, stripped_url_prefix)
40
+ return file_path if File.file?(file_path)
41
+ end
42
+ nil
43
+ end
44
+
45
+ def get_spec_urls(url)
46
+ specs_url_prefix = File.join(url_prefix.to_s, "specs")
47
+ stripped_url_prefix = strip_url_prefix(url, specs_url_prefix)
48
+ path = File.join(spec_javascripts_dir, stripped_url_prefix.to_s)
49
+ get_specs_urls_from_path(path)
50
+ end
51
+
52
+ def get_specs_urls_from_path(path=spec_javascripts_dir)
53
+ (Dir["#{path}/**/*_spec.js"] + Dir["#{path}.js"]).flatten.compact.map do |file|
54
+ file.gsub(spec_javascripts_dir, File.join(url_prefix.to_s, "specs")).gsub("//", "/")
55
+ end
56
+ end
57
+
58
+ def get_spec_file_path(url)
59
+ specs_url_prefix = File.join(url_prefix.to_s, "specs")
60
+ stripped_url_prefix = strip_url_prefix(url, specs_url_prefix)
61
+ file_path = File.join(spec_javascripts_dir, stripped_url_prefix)
62
+ file_path if File.file?(file_path)
63
+ end
64
+
65
+ def app_dir
66
+ File.join(root_dir, "app")
67
+ end
68
+
69
+ def presenters_dir
70
+ File.join(app_dir, "presenters")
71
+ end
72
+
73
+ def templates_dir
74
+ File.join(app_dir, "templates")
75
+ end
76
+
77
+ def stylesheets_dir
78
+ File.join(app_dir, "stylesheets")
79
+ end
80
+
81
+ def templates_hash
82
+ Dir["#{templates_dir}/**/*.*"].inject({}) do |memo, path|
83
+ memo[path.gsub(templates_dir, url_prefix.to_s)] = File.read(path)
84
+ memo
85
+ end
86
+ end
87
+
88
+ def javascript_urls(params={})
89
+ return [] unless File.directory?(public_javascripts_dir)
90
+ glob = params[:glob] || "**/*.js"
91
+ cache_buster = params.has_key?(:cache_bust) ? params[:cache_bust] : true
92
+ Dir["#{public_javascripts_dir}/#{glob}"].sort_by(&TrueWeb::Plugins::DirectoryFirstSort.directory_first_sort).map do |file|
93
+ asset_url(file, file.gsub(public_javascripts_dir, "#{url_prefix}/javascripts"), cache_buster)
94
+ end
95
+ end
96
+
97
+ def stylesheet_urls(params = {})
98
+ return [] unless File.directory?(stylesheets_dir)
99
+ glob = params[:glob] || "**/[^_]*.css"
100
+ cache_buster = params.has_key?(:cache_bust) ? params[:cache_bust] : true
101
+ sass_glob = glob.gsub(/\.css$/, ".sass")
102
+ Dir["#{stylesheets_dir}/#{sass_glob}"].sort_by(&TrueWeb::Plugins::DirectoryFirstSort.directory_first_sort).map do |file|
103
+ asset_url(file, file.gsub(stylesheets_dir, "#{url_prefix}/stylesheets").gsub(/\.sass$/, ".css"), cache_buster)
104
+ end
105
+ end
106
+
107
+ def spec_javascripts_dir
108
+ File.join(root_dir, "spec/javascripts")
109
+ end
110
+
111
+ def init_controllers
112
+ controllers_dir = File.join(root_dir, "app/controllers")
113
+ if File.directory?(controllers_dir)
114
+ module_files = Dir["#{controllers_dir}/**/*.module.rb"]
115
+ module_files.each do |file|
116
+ require file
117
+ end
118
+
119
+ directory_first_sort = TrueWeb::Plugins::DirectoryFirstSort.directory_first_sort
120
+ (Dir["#{controllers_dir}/**/*.rb"] - module_files).sort_by(&directory_first_sort).each do |file|
121
+ require file
122
+ end
123
+ end
124
+ end
125
+
126
+ def autoload_models
127
+ models_dir = File.join(root_dir, "app/models")
128
+ if File.directory?(models_dir)
129
+ directory_first_sort = TrueWeb::Plugins::DirectoryFirstSort.directory_first_sort
130
+ Dir["#{models_dir}/**/*.rb"].sort_by(&directory_first_sort).each do |file|
131
+ const_name_parts = file.
132
+ gsub(models_dir, "").
133
+ gsub("-", "_").
134
+ gsub(/\.rb/, "").
135
+ camelize.
136
+ split("::").
137
+ select {|part| part.present?}
138
+ parent_const = const_name_parts[0..-2].join("::").constantize
139
+ parent_const.autoload const_name_parts[-1].to_sym, file
140
+ end
141
+ end
142
+ end
143
+
144
+ def public_dir
145
+ File.join(root_dir, "public")
146
+ end
147
+
148
+ protected
149
+ def asset_url(file, url_path, cache_buster)
150
+ if cache_buster
151
+ "#{url_path}?_cb=#{File.mtime(file).to_i}"
152
+ else
153
+ url_path
154
+ end
155
+ end
156
+
157
+ def static_file_dirs
158
+ [public_dir, templates_dir]
159
+ end
160
+
161
+ def public_javascripts_dir
162
+ File.join(public_dir, "javascripts")
163
+ end
164
+
165
+ def strip_url_prefix(url_path, prefix=url_prefix)
166
+ url_path.gsub(Regexp.new("^#{prefix}"), "")
167
+ end
168
+
169
+ def eval_init_rb
170
+ init_rb_path = "#{root_dir}/init.rb"
171
+ if File.exists?(init_rb_path)
172
+ instance_eval(File.read(init_rb_path), init_rb_path, 1)
173
+ end
174
+ end
175
+ end
176
+ end