pakyow-core 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. data/pakyow-core/CHANGES +3 -0
  2. data/pakyow-core/MIT-LICENSE +20 -0
  3. data/pakyow-core/README +1 -0
  4. data/pakyow-core/bin/pakyow +14 -0
  5. data/pakyow-core/lib/commands/USAGE +8 -0
  6. data/pakyow-core/lib/commands/USAGE-NEW +11 -0
  7. data/pakyow-core/lib/commands/USAGE-SERVER +12 -0
  8. data/pakyow-core/lib/commands/server.rb +8 -0
  9. data/pakyow-core/lib/core/application.rb +463 -0
  10. data/pakyow-core/lib/core/base.rb +17 -0
  11. data/pakyow-core/lib/core/configuration/app.rb +73 -0
  12. data/pakyow-core/lib/core/configuration/base.rb +32 -0
  13. data/pakyow-core/lib/core/configuration/server.rb +19 -0
  14. data/pakyow-core/lib/core/helpers.rb +22 -0
  15. data/pakyow-core/lib/core/loader.rb +35 -0
  16. data/pakyow-core/lib/core/log.rb +35 -0
  17. data/pakyow-core/lib/core/presenter_base.rb +7 -0
  18. data/pakyow-core/lib/core/request.rb +66 -0
  19. data/pakyow-core/lib/core/route_store.rb +117 -0
  20. data/pakyow-core/lib/generators/pakyow/app/app_generator.rb +26 -0
  21. data/pakyow-core/lib/generators/pakyow/app/templates/README +54 -0
  22. data/pakyow-core/lib/generators/pakyow/app/templates/app/lib/application_controller.rb +6 -0
  23. data/pakyow-core/lib/generators/pakyow/app/templates/app/views/main.html +1 -0
  24. data/pakyow-core/lib/generators/pakyow/app/templates/app/views/pakyow.html +12 -0
  25. data/pakyow-core/lib/generators/pakyow/app/templates/config/application.rb +18 -0
  26. data/pakyow-core/lib/generators/pakyow/app/templates/config.ru +10 -0
  27. data/pakyow-core/lib/generators/pakyow/app/templates/logs/requests.log +0 -0
  28. data/pakyow-core/lib/generators/pakyow/app/templates/public/favicon.ico +0 -0
  29. data/pakyow-core/lib/generators/pakyow/app/templates/rakefile +5 -0
  30. data/pakyow-core/lib/pakyow-core.rb +14 -0
  31. data/pakyow-core/lib/utils/dir.rb +18 -0
  32. data/pakyow-core/lib/utils/hash.rb +31 -0
  33. data/pakyow-core/lib/utils/string.rb +37 -0
  34. metadata +113 -0
@@ -0,0 +1,22 @@
1
+ module Pakyow
2
+
3
+ # Helper methods that simply provide information (for use in binders)
4
+ module GeneralHelpers
5
+ def request
6
+ Pakyow.app.request
7
+ end
8
+
9
+ def response
10
+ Pakyow.app.response
11
+ end
12
+ end
13
+
14
+ # Helper methods specific to delegates and controllers.
15
+ module Helpers
16
+ include GeneralHelpers
17
+
18
+ def app
19
+ Pakyow.app
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,35 @@
1
+ module Pakyow
2
+
3
+ # Handles the loading and reloading of a Pakyow application. If in development
4
+ # mode, files are automatically reloaded if modified.
5
+ class Loader
6
+
7
+ # Loads files in the provided path, decending into child directories.
8
+ def load!(path)
9
+ require_recursively(path)
10
+ end
11
+
12
+ protected
13
+
14
+ def require_recursively(dir)
15
+ @times ||= {}
16
+ if File.exists?(dir)
17
+ DirUtils.walk_dir(dir) do |path|
18
+ next if FileTest.directory?(path)
19
+
20
+ split = path.split('/')
21
+ next if split[split.length-1].start_with?('.')
22
+
23
+ if Configuration::Base.app.auto_reload
24
+ if !@times[path] || (@times[path] && File.mtime(path) - @times[path] > 0)
25
+ load(path)
26
+ @times[path] = File.mtime(path)
27
+ end
28
+ else
29
+ require path
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,35 @@
1
+ module Pakyow
2
+
3
+ # Provides an easy way to log text, warnings, etc.
4
+ class Log
5
+
6
+ # Adds text to the log.
7
+ def self.puts(text = "")
8
+ return if !Configuration::Base.app.log
9
+
10
+ @@console ||= Logger.new($stdout)
11
+ @@console << "#{text}\r\n"
12
+
13
+ dir = "#{Configuration::Base.app.log_dir}"
14
+
15
+ if File.exists?(dir)
16
+ @@file ||= Logger.new("#{dir}/#{Configuration::Base.app.log_name}")
17
+ @@file << "#{text}\r\n"
18
+ end
19
+ end
20
+
21
+ class << self
22
+ alias :enter :puts
23
+ end
24
+
25
+ # Adds warning text to the log.
26
+ def self.warn(text)
27
+ Log.enter("WARNING: #{text}")
28
+ end
29
+
30
+ # Adds error text to the log.
31
+ def self.error(text)
32
+ Log.enter("ERROR: #{text}")
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,7 @@
1
+ module Pakyow
2
+ class PresenterBase
3
+ def self.inherited(subclass)
4
+ Configuration::Base.app.presenter = subclass
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,66 @@
1
+ module Pakyow
2
+
3
+ # The Request object.
4
+ class Request < Rack::Request
5
+ attr_accessor :restful, :route_spec, :controller, :action, :format, :error
6
+
7
+ # Easy access to path_info.
8
+ def path
9
+ self.path_info
10
+ end
11
+
12
+ # Determines the request method.
13
+ def method
14
+ request_method.downcase.to_sym
15
+ end
16
+
17
+ def format=(format)
18
+ @format = format ? format.to_sym : :html
19
+
20
+ # Set response type
21
+ Pakyow.app.response["Content-Type"] = Rack::Mime.mime_type(".#{@format}")
22
+ end
23
+
24
+ def session
25
+ env['rack.session'] || {}
26
+ end
27
+
28
+ def cookies
29
+ @cookies ||= HashUtils.strhash(super)
30
+ end
31
+
32
+ # Returns indifferent params (see {HashUtils.strhash} for more info on indifferent hashes).
33
+ def params
34
+ @params ||= HashUtils.strhash(super)
35
+ end
36
+
37
+ # Returns array of url components.
38
+ def url_parts
39
+ unless @url
40
+ @url = self.class.split_url(self.env['PATH_INFO'])
41
+ end
42
+
43
+ return @url
44
+ end
45
+
46
+ # Returns array of referer components.
47
+ def referer_parts
48
+ unless @referer
49
+ @referer = self.class.split_url(self.env['HTTP_REFERER'])
50
+ end
51
+
52
+ return @referer
53
+ end
54
+
55
+ private
56
+
57
+ def self.split_url(url)
58
+ arr = []
59
+ url.split('/').each { |r|
60
+ arr << r unless r.empty?
61
+ }
62
+
63
+ return arr
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,117 @@
1
+ module Pakyow
2
+ class RouteStore
3
+
4
+ def initialize()
5
+ @order = 1
6
+ @store =
7
+ {
8
+ # string routes are stored, for each method, as a hash of 'route'=>{:block=>b,:order=>n}
9
+ :string => {:get=>{}, :post=>{}, :put=>{}, :delete=>{}},
10
+
11
+ # regex routes are stored, for each method, as an array of hashes {:regex=>r,:block=>b,:order=>n,:vars=>{n=>var}}
12
+ # they are in definition order in the array
13
+ :regex => {:get=>[], :post=>[], :put=>[], :delete=>[]}
14
+
15
+ # :order is a global order across both string and regex routes.
16
+ }
17
+ end
18
+
19
+ def add_route(route_spec, block, method, data)
20
+ route_spec = normalize_route(route_spec)
21
+ route_to_match, vars = extract_route_vars(route_spec)
22
+ if route_to_match.class == String
23
+ @store[:string][method][route_to_match]={:block => block,
24
+ :order => @order,
25
+ :data => data}
26
+ @order = @order + 1
27
+ elsif route_to_match.class == Regexp
28
+ @store[:regex][method] << {:regex => route_to_match,
29
+ :block => block,
30
+ :order => @order,
31
+ :vars => vars,
32
+ :data => data}
33
+ @order = @order + 1
34
+ end
35
+ end
36
+
37
+ # returns block, {:vars=>{:var=>matched_value, ...}, :data=>data}
38
+ def get_block(route, method)
39
+ route = normalize_route(route)
40
+ # Get the match for a string route
41
+ string_route_match = @store[:string][method][route]
42
+
43
+ # Get first regex match
44
+ regex_route_match = nil
45
+ match_data = nil
46
+ @store[:regex][method].each { |rinfo|
47
+ if match_data = rinfo[:regex].match(route)
48
+ regex_route_match = rinfo
49
+ break
50
+ end
51
+ }
52
+
53
+ # return block for match with smaller :order
54
+ if string_route_match && regex_route_match
55
+ if string_route_match[:order] < regex_route_match[:order]
56
+ data = string_route_match[:data]
57
+ return string_route_match[:block], {:vars=>{}, :data=>data}
58
+ else
59
+ data = regex_route_match[:data]
60
+ return regex_route_match[:block], {:vars=>build_regex_var_values(regex_route_match[:vars], match_data), :data=>data}
61
+ end
62
+ elsif string_route_match
63
+ data = string_route_match[:data]
64
+ return string_route_match[:block], {:vars=>{}, :data=>data}
65
+ elsif regex_route_match
66
+ data = regex_route_match[:data]
67
+ return regex_route_match[:block], {:vars=>build_regex_var_values(regex_route_match[:vars], match_data), :data=>data}
68
+ else
69
+ return nil, {:vars=>{}, :data=>nil}
70
+ end
71
+
72
+ end
73
+
74
+ private
75
+
76
+ # Returns a regex and an array of variable info
77
+ def extract_route_vars(route_spec)
78
+ return route_spec, [] if route_spec.is_a?(Regexp)
79
+
80
+ unless route_spec[0,1] == ':' || route_spec.index('/:')
81
+ return route_spec, []
82
+ end
83
+
84
+ vars = []
85
+ position_counter = 0
86
+ regex_route = route_spec
87
+ route_spec.split('/').each_with_index do |segment, i|
88
+ if segment.include?(':')
89
+ position_counter += 1
90
+ vars << { :position => position_counter, :var => segment.gsub(':', '').to_sym }
91
+ regex_route = regex_route.gsub(segment, '([^new/]+)')
92
+ end
93
+ end
94
+
95
+ reg = Regexp.new("^#{regex_route}$")
96
+
97
+ return reg, vars
98
+ end
99
+
100
+ # remove leading/trailing forward slashes
101
+ def normalize_route(route_spec)
102
+ return route_spec if route_spec.is_a?(Regexp)
103
+ route_spec = route_spec[1, route_spec.length - 1] if route_spec[0, 1] == '/'
104
+ route_spec = route_spec[0, route_spec.length - 1] if route_spec[route_spec.length - 1, 1] == '/'
105
+ route_spec
106
+ end
107
+
108
+ def build_regex_var_values(vars_info, match_data)
109
+ var_values = {}
110
+ vars_info.each { |vi|
111
+ var_values[vi[:var]] = match_data[vi[:position]]
112
+ }
113
+ var_values
114
+ end
115
+
116
+ end
117
+ end
@@ -0,0 +1,26 @@
1
+ require 'fileutils'
2
+
3
+ module Pakyow
4
+ module Generators
5
+ class AppGenerator
6
+ class << self
7
+ def start
8
+ if ARGV.first == '--help' || ARGV.first == '-h'
9
+ puts File.open(File.join(CORE_PATH, 'commands/USAGE-NEW')).read
10
+ else
11
+ generator = self.new
12
+ generator.build(ARGV.first)
13
+ end
14
+ end
15
+ end
16
+
17
+ def initialize
18
+ @src = "#{File.expand_path('../', __FILE__)}/templates/."
19
+ end
20
+
21
+ def build(dest)
22
+ FileUtils.cp_r(@src, dest)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,54 @@
1
+ # Introduction
2
+
3
+ Pakyow is a web framework for Ruby that knocks out projects with a serious
4
+ punch. Pound for pound its the best way to build a web app. Get ready to rumble.
5
+
6
+ Pakyow brings a unique approach to development:
7
+
8
+ ## Views are views.
9
+ Views are 100% HTML, no template language required. The view has finally been
10
+ freed from logic.
11
+
12
+ ## Views are data aware.
13
+ A view knows what it presents. Use this to create powerful connections between
14
+ business logic and views.
15
+
16
+ ## Keep you moving forward.
17
+ Prototype an app by building the views first. Then write the view logic
18
+ without changing a single view.
19
+
20
+ There are two main components of Pakyow. The first is Pakyow Core, which
21
+ handles routing requests to business logic. The second component is Pakyow
22
+ Presenter, which gives an application the ability to have a presentation
23
+ layer and provides mechanisms for the controller to bind data to the
24
+ presentation layer. Pakyow Core can operate independently of Pakyow
25
+ Presenter for those cases where an application doesn't need a presentation layer.
26
+
27
+ # Getting Started
28
+
29
+ 1. Install Pakyow:
30
+
31
+ gem install pakyow
32
+
33
+ 2. Create a new Pakyow application from the command prompt:
34
+
35
+ pakyow new webapp
36
+
37
+ 3. Move to the "webapp" directory and start the application:
38
+
39
+ cd webapp; pakyow server
40
+
41
+ 4. You'll find the application running here: http://localhost:3000
42
+
43
+ # Next Steps
44
+
45
+ The following resources might be handy:
46
+
47
+ Website:
48
+ http://pakyow.com
49
+
50
+ Manual:
51
+ http://pakyow.com/manual
52
+
53
+ Code:
54
+ http://github.com/metabahn/pakyow
@@ -0,0 +1,6 @@
1
+ class ApplicationController
2
+ include Pakyow::Helpers
3
+
4
+ def index
5
+ end
6
+ end
@@ -0,0 +1 @@
1
+ <h1>Welcome to Pakyow!</h1>
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Pakyow</title>
5
+ </head>
6
+
7
+ <body>
8
+ <div id="wrapper">
9
+ <div id="main"></div>
10
+ </div>
11
+ </body>
12
+ </html>
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'pakyow'
3
+
4
+ module PakyowApplication
5
+ class Application < Pakyow::Application
6
+ config.app.default_environment = :development
7
+
8
+ configure(:development) do
9
+ end
10
+
11
+ routes do
12
+ default :ApplicationController, :index
13
+ end
14
+
15
+ middleware do
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,10 @@
1
+ require 'config/application'
2
+ PakyowApplication::Application.stage(:development)
3
+
4
+ app = Rack::Builder.new do
5
+ # Needed for Pakyow to work
6
+ use Rack::MethodOverride
7
+ run PakyowApplication::Application.new
8
+ end.to_app
9
+
10
+ run(app)
@@ -0,0 +1,5 @@
1
+ env = ARGV[1] || 'development'
2
+ env = env.split('=')[1] || env
3
+
4
+ require 'config/application'
5
+ PakyowApplication::Application.stage(env.to_sym)
@@ -0,0 +1,14 @@
1
+ libdir = File.dirname(__FILE__)
2
+ $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
3
+
4
+ # Gems
5
+ require 'find'
6
+ require 'rack'
7
+ require 'rack/file'
8
+ require 'logger'
9
+ require 'cgi'
10
+
11
+ # Base
12
+ autoload :Pakyow, 'core/base'
13
+
14
+ include Pakyow
@@ -0,0 +1,18 @@
1
+ module Pakyow
2
+
3
+ # Utility methods for directories and files.
4
+ class DirUtils
5
+
6
+ # visit dir, then all files in dir, then walk_dir each directory in dir
7
+ def self.walk_dir(dir, &block)
8
+ yield dir
9
+ all = Dir.entries(dir)
10
+ partition = all.partition{|e| File.file?("#{dir}/#{e}")}
11
+ files = partition[0]
12
+ dirs = partition[1]
13
+ files.each{|f| yield "#{dir}/#{f}" unless f.start_with?(".")}
14
+ dirs.each{|d| walk_dir("#{dir}/#{d}", &block) unless d.start_with?(".")}
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,31 @@
1
+ module Pakyow
2
+
3
+ # Utility methods for hashes.
4
+ class HashUtils
5
+ # Creates an indifferent hash. This means that when indifferentized, this hash:
6
+ # { 'foo' => 'bar' }
7
+ #
8
+ # Can be accessed like this:
9
+ # { :foo => 'bar' }
10
+ #
11
+ def self.strhash(hash)
12
+ indifferentize(hash)
13
+ end
14
+
15
+ protected
16
+
17
+ # (see {strhash})
18
+ def self.indifferentize(hash)
19
+ hash.each_pair do |key, value|
20
+ hash[key] = indifferentize(value) if value.is_a? Hash
21
+ end
22
+
23
+ indifferent_hash.merge(hash)
24
+ end
25
+
26
+ # (see {strhash})
27
+ def self.indifferent_hash
28
+ Hash.new { |hash,key| hash[key.to_s] if Symbol === key }
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,37 @@
1
+ module Pakyow
2
+
3
+ # Utility methods for strings.
4
+ class StringUtils
5
+
6
+ # Creates an underscored, lowercase version of a string.
7
+ # This was borrowed from another library, probably ActiveSupport.
8
+ def self.underscore(string)
9
+ string.gsub(/::/, '/').
10
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
11
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
12
+ tr("-", "_").
13
+ downcase
14
+ end
15
+
16
+ # split . seperated string at the last .
17
+ def self.split_at_last_dot(s)
18
+ split_index = s.rindex('.')
19
+ return s,nil unless split_index
20
+ left = s[0,split_index]
21
+ right = s[split_index+1,s.length-(split_index+1)]
22
+ return left,right
23
+ end
24
+
25
+ def self.remove_route_vars(route_spec)
26
+ return unless route_spec
27
+ arr = route_spec.split('/')
28
+ new_arr = []
29
+ arr.each {|e| new_arr << e unless e[0,1] == ':'}
30
+ ret = new_arr.join('/')
31
+ return '/' if ret == ''
32
+ return ret
33
+ end
34
+
35
+
36
+ end
37
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pakyow-core
3
+ version: !ruby/object:Gem::Version
4
+ hash: 5
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 6
9
+ - 1
10
+ version: 0.6.1
11
+ platform: ruby
12
+ authors:
13
+ - Bryan Powell
14
+ autorequire:
15
+ bindir: pakyow-core/bin
16
+ cert_chain: []
17
+
18
+ date: 2011-08-20 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rack
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 11
29
+ segments:
30
+ - 1
31
+ - 2
32
+ version: "1.2"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ description: pakyow-core
36
+ email: bryan@metabahn.com
37
+ executables:
38
+ - pakyow
39
+ extensions: []
40
+
41
+ extra_rdoc_files: []
42
+
43
+ files:
44
+ - pakyow-core/CHANGES
45
+ - pakyow-core/README
46
+ - pakyow-core/MIT-LICENSE
47
+ - pakyow-core/lib/commands/server.rb
48
+ - pakyow-core/lib/commands/USAGE
49
+ - pakyow-core/lib/commands/USAGE-NEW
50
+ - pakyow-core/lib/commands/USAGE-SERVER
51
+ - pakyow-core/lib/core/application.rb
52
+ - pakyow-core/lib/core/base.rb
53
+ - pakyow-core/lib/core/configuration/app.rb
54
+ - pakyow-core/lib/core/configuration/base.rb
55
+ - pakyow-core/lib/core/configuration/server.rb
56
+ - pakyow-core/lib/core/helpers.rb
57
+ - pakyow-core/lib/core/loader.rb
58
+ - pakyow-core/lib/core/log.rb
59
+ - pakyow-core/lib/core/presenter_base.rb
60
+ - pakyow-core/lib/core/request.rb
61
+ - pakyow-core/lib/core/route_store.rb
62
+ - pakyow-core/lib/generators/pakyow/app/app_generator.rb
63
+ - pakyow-core/lib/generators/pakyow/app/templates/app/lib/application_controller.rb
64
+ - pakyow-core/lib/generators/pakyow/app/templates/app/views/main.html
65
+ - pakyow-core/lib/generators/pakyow/app/templates/app/views/pakyow.html
66
+ - pakyow-core/lib/generators/pakyow/app/templates/config/application.rb
67
+ - pakyow-core/lib/generators/pakyow/app/templates/config.ru
68
+ - pakyow-core/lib/generators/pakyow/app/templates/logs/requests.log
69
+ - pakyow-core/lib/generators/pakyow/app/templates/public/favicon.ico
70
+ - pakyow-core/lib/generators/pakyow/app/templates/rakefile
71
+ - pakyow-core/lib/generators/pakyow/app/templates/README
72
+ - pakyow-core/lib/pakyow-core.rb
73
+ - pakyow-core/lib/utils/dir.rb
74
+ - pakyow-core/lib/utils/hash.rb
75
+ - pakyow-core/lib/utils/string.rb
76
+ - pakyow-core/bin/pakyow
77
+ homepage: http://pakyow.com
78
+ licenses: []
79
+
80
+ post_install_message:
81
+ rdoc_options: []
82
+
83
+ require_paths:
84
+ - pakyow-core/lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ hash: 57
91
+ segments:
92
+ - 1
93
+ - 8
94
+ - 7
95
+ version: 1.8.7
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ hash: 3
102
+ segments:
103
+ - 0
104
+ version: "0"
105
+ requirements: []
106
+
107
+ rubyforge_project: pakyow-core
108
+ rubygems_version: 1.8.8
109
+ signing_key:
110
+ specification_version: 3
111
+ summary: pakyow-core
112
+ test_files: []
113
+