doozer 0.2.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 (104) hide show
  1. data/.document +5 -0
  2. data/.gitignore +5 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +57 -0
  5. data/Rakefile +62 -0
  6. data/VERSION +1 -0
  7. data/bin/doozer +6 -0
  8. data/doozer.gemspec +156 -0
  9. data/lib/doozer.rb +35 -0
  10. data/lib/doozer/active_support/array.rb +14 -0
  11. data/lib/doozer/active_support/class.rb +221 -0
  12. data/lib/doozer/active_support/date_time.rb +23 -0
  13. data/lib/doozer/active_support/object.rb +43 -0
  14. data/lib/doozer/active_support/time.rb +32 -0
  15. data/lib/doozer/app.rb +294 -0
  16. data/lib/doozer/configs.rb +146 -0
  17. data/lib/doozer/controller.rb +340 -0
  18. data/lib/doozer/exceptions.rb +12 -0
  19. data/lib/doozer/extend.rb +10 -0
  20. data/lib/doozer/initializer.rb +104 -0
  21. data/lib/doozer/lib.rb +32 -0
  22. data/lib/doozer/logger.rb +12 -0
  23. data/lib/doozer/orm/active_record.rb +28 -0
  24. data/lib/doozer/orm/data_mapper.rb +22 -0
  25. data/lib/doozer/orm/sequel.rb +21 -0
  26. data/lib/doozer/partial.rb +99 -0
  27. data/lib/doozer/plugins/paginate/init.rb +2 -0
  28. data/lib/doozer/plugins/paginate/lib/paginate.rb +32 -0
  29. data/lib/doozer/plugins/paginate/lib/paginate/collection.rb +60 -0
  30. data/lib/doozer/plugins/paginate/lib/paginate/finder.rb +116 -0
  31. data/lib/doozer/plugins/paginate/lib/paginate/view_helpers.rb +37 -0
  32. data/lib/doozer/rackup/server.ru +35 -0
  33. data/lib/doozer/rackup/test.rb +20 -0
  34. data/lib/doozer/redirect.rb +12 -0
  35. data/lib/doozer/route.rb +292 -0
  36. data/lib/doozer/scripts/cluster.rb +126 -0
  37. data/lib/doozer/scripts/console.rb +2 -0
  38. data/lib/doozer/scripts/migrate.rb +108 -0
  39. data/lib/doozer/scripts/task.rb +60 -0
  40. data/lib/doozer/scripts/test.rb +23 -0
  41. data/lib/doozer/version.rb +8 -0
  42. data/lib/doozer/view_helpers.rb +251 -0
  43. data/lib/doozer/watcher.rb +369 -0
  44. data/lib/generator/generator.rb +548 -0
  45. data/templates/skeleton/Rakefile +3 -0
  46. data/templates/skeleton/app/controllers/application_controller.rb +2 -0
  47. data/templates/skeleton/app/controllers/index_controller.rb +7 -0
  48. data/templates/skeleton/app/helpers/application_helper.rb +17 -0
  49. data/templates/skeleton/app/views/global/_header.html.erb +7 -0
  50. data/templates/skeleton/app/views/global/_navigation.html.erb +6 -0
  51. data/templates/skeleton/app/views/index/index.html.erb +108 -0
  52. data/templates/skeleton/app/views/layouts/default.html.erb +23 -0
  53. data/templates/skeleton/config/app.yml +31 -0
  54. data/templates/skeleton/config/boot.rb +17 -0
  55. data/templates/skeleton/config/database.yml +25 -0
  56. data/templates/skeleton/config/environment.rb +11 -0
  57. data/templates/skeleton/config/rack.rb +30 -0
  58. data/templates/skeleton/config/routes.rb +69 -0
  59. data/templates/skeleton/script/cluster +4 -0
  60. data/templates/skeleton/script/console +15 -0
  61. data/templates/skeleton/script/migrate +4 -0
  62. data/templates/skeleton/script/task +4 -0
  63. data/templates/skeleton/script/test +4 -0
  64. data/templates/skeleton/static/404.html +16 -0
  65. data/templates/skeleton/static/500.html +16 -0
  66. data/templates/skeleton/static/css/style.css +32 -0
  67. data/templates/skeleton/static/favicon.ico +0 -0
  68. data/templates/skeleton/static/js/application.js +1 -0
  69. data/templates/skeleton/static/js/jquery-1.3.min.js +19 -0
  70. data/templates/skeleton/static/robots.txt +5 -0
  71. data/templates/skeleton/test/fixtures/setup.rb +6 -0
  72. data/templates/skeleton/test/setup.rb +33 -0
  73. data/test/doozer_test.rb +7 -0
  74. data/test/project/Rakefile +3 -0
  75. data/test/project/app/controllers/application_controller.rb +2 -0
  76. data/test/project/app/controllers/index_controller.rb +7 -0
  77. data/test/project/app/helpers/application_helper.rb +17 -0
  78. data/test/project/app/views/global/_header.html.erb +7 -0
  79. data/test/project/app/views/global/_navigation.html.erb +6 -0
  80. data/test/project/app/views/index/index.html.erb +108 -0
  81. data/test/project/app/views/layouts/default.html.erb +23 -0
  82. data/test/project/config/app.yml +31 -0
  83. data/test/project/config/boot.rb +17 -0
  84. data/test/project/config/database.yml +25 -0
  85. data/test/project/config/environment.rb +11 -0
  86. data/test/project/config/rack.rb +30 -0
  87. data/test/project/config/routes.rb +72 -0
  88. data/test/project/script/cluster +4 -0
  89. data/test/project/script/console +15 -0
  90. data/test/project/script/migrate +4 -0
  91. data/test/project/script/task +4 -0
  92. data/test/project/script/test +4 -0
  93. data/test/project/static/404.html +16 -0
  94. data/test/project/static/500.html +16 -0
  95. data/test/project/static/css/style.css +32 -0
  96. data/test/project/static/favicon.ico +0 -0
  97. data/test/project/static/js/application.js +1 -0
  98. data/test/project/static/js/jquery-1.3.min.js +19 -0
  99. data/test/project/static/robots.txt +5 -0
  100. data/test/project/test/fixtures/setup.rb +6 -0
  101. data/test/project/test/setup.rb +33 -0
  102. data/test/routing_test.rb +66 -0
  103. data/test/test_helper.rb +26 -0
  104. metadata +169 -0
@@ -0,0 +1,2 @@
1
+ require 'doozer'
2
+ Doozer::Initializer.console(@env)
@@ -0,0 +1,108 @@
1
+ #= Migrations
2
+ # This file is required in script/migrate. It loads the specified migration from the project/db directory and runs the migration with the specified direction.
3
+ # Navigate to your project root and run it with the following commands.
4
+ #
5
+ # script/migrate
6
+ # -V version:direction (example: 1:up || 1:down)
7
+ # -E environment (default: development || deployment)
8
+ # -h Hellllpppp!!!
9
+ #
10
+ #== Examples
11
+ #
12
+ # Suppose you have this file db/001_initial_schema.rb
13
+ #
14
+ #== Example for ActiveRecord
15
+ #
16
+ # class InitialSchema < ActiveRecord::Migration
17
+ # def self.up
18
+ # end
19
+ # def self.down
20
+ # end
21
+ # end
22
+ #
23
+ #
24
+ #== Example for DataMapper
25
+ #
26
+ # require 'dm-more'
27
+ # class CreateUser
28
+ # def self.up
29
+ # end
30
+ # def self.down
31
+ # end
32
+ # end
33
+ #
34
+ #== Example for Sequel
35
+ #
36
+ # class InitialSchema
37
+ # def self.db
38
+ # Doozer::Configs.db
39
+ # end
40
+ # def self.up
41
+ # db.create_table :examples do
42
+ # end
43
+ # end
44
+ # def self.down
45
+ # db.drop_table :examples
46
+ # end
47
+ # end
48
+
49
+ require 'optparse'
50
+ @env = :development
51
+ @version = nil
52
+ @direction = nil
53
+
54
+ opts = OptionParser.new("", 24, ' ') { |opts|
55
+ opts.banner = "Usage: script/migrate -V number:direction -E (default: development || deployment)"
56
+ opts.separator ""
57
+ opts.separator "Command options:"
58
+
59
+ opts.on("-E", "--env ENVIRONMENT", "use ENVIRONMENT for defaults (default: development || deployment)") { |e|
60
+ @env = e.to_sym
61
+ }
62
+
63
+ opts.on("-V", "--version VERSION", "use VERSION to upgrade or downgrade to the correct version number") { | v |
64
+ if v.index(":up")
65
+ @direction = :up
66
+ elsif v.index(":down")
67
+ @direction = :down
68
+ else
69
+ raise "Missing direction. Must be -V (num:up || num:down)"
70
+ end
71
+ @version = v.split(":")[0].to_i
72
+ }
73
+ opts.on_tail("-h", "--help", "Show this message") do
74
+ puts opts
75
+ exit
76
+ end
77
+
78
+ opts.parse! ARGV
79
+ }
80
+
81
+ raise "Missing Version and Direction in form of version:direction" if @version.nil? or @direction.nil?
82
+
83
+ #--boot it up
84
+ Doozer::Initializer.boot(@env)
85
+
86
+ # need to grab all the current migrations. assumes there isn't a migration with 000_*_.rb
87
+ migrations = [nil].concat( Dir.glob(File.join(APP_PATH,'db/*_*.rb')) )
88
+
89
+ p "Loading migration files"
90
+ p "Version: #{@version}"
91
+ p "Direction: #{@direction}"
92
+
93
+ if @version > 0
94
+ file = migrations[@version]
95
+ raise "Can't find file for this migration" if file.nil?
96
+ require file
97
+ p "Migrating #{file}"
98
+ klass = file.split("/").last.gsub(/\.rb/,"").split('_')
99
+ klass = Doozer::Lib.classify(klass.slice(1, klass.length).join('_'))
100
+ obj = Object.const_get(klass)
101
+
102
+ case @direction
103
+ when :up
104
+ obj.up
105
+ when :down
106
+ obj.down
107
+ end
108
+ end
@@ -0,0 +1,60 @@
1
+ #= Tasks
2
+ # This file is required in script/task.
3
+ # Add files to /tasks where the specified task_name contains a class with TaskName and a 'run' class method.
4
+ # Running a task automatically loads Doozer::Config and the specified ORM. You must require all other files your tasks require beyond these.
5
+ # Navigate to your app root and run it with the following commands.
6
+ #
7
+ # script/clusters
8
+ # -T task_name
9
+ # -E environment (default: development || deployment)
10
+ # -h Hellllpppp!!!
11
+ #
12
+ #== Example
13
+ # Suppose you have this file tasks/who_rocks.rb
14
+ #
15
+ # class WhoRocks
16
+ # def self.run
17
+ # p "You Do!"
18
+ # end
19
+ # end
20
+ #
21
+ # run: script/task -T who_rocks
22
+ require 'optparse'
23
+ @env = :development
24
+ @task = nil
25
+
26
+ opts = OptionParser.new("", 24, ' ') { |opts|
27
+ opts.banner = "Usage: script/task -T task_name -E (default: development || deployment || test)"
28
+ opts.separator ""
29
+ opts.separator "Command options:"
30
+
31
+ opts.on("-E", "--env ENVIRONMENT", "use ENVIRONMENT for defaults (default: development || deployment || test)") { |e|
32
+ @env = e.to_sym
33
+ }
34
+
35
+ opts.on("-T", "--task TASK", "run task_name") { | t |
36
+ @task = t
37
+ }
38
+
39
+ opts.on_tail("-h", "--help", "Show this message") do
40
+ puts opts
41
+ exit
42
+ end
43
+
44
+ opts.parse! ARGV
45
+ }
46
+
47
+ raise "Missing task_name" if @task.nil?
48
+
49
+ #--boot it up
50
+ Doozer::Initializer.boot(@env)
51
+
52
+ if @task
53
+ file = File.join(APP_PATH, "tasks/#{@task}.rb")
54
+ raise "Can't find this task file #{@task}" if file.nil?
55
+ p "Running #{@task}"
56
+ klass = file.split("/").last
57
+ require file
58
+ klass = Doozer::Lib.classify(klass.gsub(/\.rb/,""))
59
+ Object.const_get(klass).run
60
+ end
@@ -0,0 +1,23 @@
1
+ # #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ @command = nil
4
+
5
+ opts = OptionParser.new("", 24, ' ') { |opts|
6
+ opts.banner = "Usage: script/test [command]"
7
+
8
+ opts.separator ""
9
+ opts.separator "Command options:"
10
+ opts.on("-C", "--command COMMAND", "setup (not implemented yet: unit, functional)") { | c |
11
+ @command = c.downcase.to_sym if c
12
+ }
13
+ opts.on_tail("-h", "--help", "Show this message") do
14
+ puts opts
15
+ exit
16
+ end
17
+ opts.parse! ARGV
18
+ }
19
+
20
+ case @command
21
+ when :setup
22
+ require 'test/setup'
23
+ end
@@ -0,0 +1,8 @@
1
+ module Doozer
2
+ module Version
3
+ MAJOR=0
4
+ MINOR=2
5
+ PATCH=0
6
+ STRING=[MAJOR, MINOR, PATCH].join('.')
7
+ end
8
+ end
@@ -0,0 +1,251 @@
1
+ require 'digest/sha1'
2
+
3
+ module Doozer
4
+
5
+ # ViewHelpers which are included in Controllers and Partials
6
+ module ViewHelpers
7
+
8
+ # Returns a url from a hash of options. Expects option keys as symbols.
9
+ #
10
+ # :name - the route.name to parse additional options with
11
+ #
12
+ # :base_url - the base url of the request
13
+ #
14
+ # => route tokens are replace the key/values pairs in the options. if a route token is found in the options it is replaced with a 'MISSING-key' string.
15
+ #
16
+ # => all remaining options are added as key=value query string parameters
17
+ #
18
+ # You can also pass a opt as a string which just passed it through.
19
+ #
20
+ def url(opt)
21
+ url = ''
22
+ if opt.kind_of? Hash
23
+ # name (if present) trumps controller/action (if present)
24
+ if opt[:name]
25
+ # TODO: this needs to be only in dev mode
26
+ name = opt.delete(:name)
27
+ route = Doozer::Routing::Routes::get_by_name(name)
28
+ return "MISSING-ROUTE-for-name-#{name}" if route .nil?
29
+ url = "#{route.path}"
30
+
31
+ # we need to swap out the tokens here and account for formats on the end of the path
32
+ tokens = route.tokens
33
+ tokens.last.gsub!(Regexp.compile("\.#{route.format.to_s}$"), '') if route.format != :html if not route.tokens.empty?
34
+ tokens.each { |token|
35
+ val = opt[token.to_sym]
36
+ if val
37
+ opt.delete(token.to_sym)
38
+ else
39
+ val = "MISSING-#{token}"
40
+ end
41
+ url.gsub!(/:#{token}/, val.to_s)
42
+ }
43
+ end
44
+
45
+ # set base_url
46
+ host = ""
47
+ if opt[:base_url]
48
+ host = opt.delete(:base_url)
49
+ end
50
+ # add qs pairs
51
+ if not opt.empty?
52
+ url += "?#{hash_to_qs(opt)}"
53
+ end
54
+ url = "#{host}#{url}"
55
+ elsif opt.kind_of? String
56
+ url = "#{opt}"
57
+ end
58
+ return url
59
+ end
60
+
61
+ # Creates an html anchor tag.
62
+ #
63
+ # text - the text of the anchor tag
64
+ #
65
+ # opt - a hash of options which are passed to url(opt)
66
+ #
67
+ # prop - a hash of anchor tag attributes to add to the link
68
+ def link(text='', opt={}, prop={})
69
+ "<a href=\"#{url(opt)}\"#{hash_to_props(prop)}>#{text}</a>"
70
+ end
71
+
72
+ # Creates an img tag.
73
+ #
74
+ # path - the src of the image tag
75
+ #
76
+ # prop - a hash of image tag attributes
77
+ def img(path, prop={})
78
+ path = timestamp_path(path)
79
+ "<img src=\"#{path}\"#{hash_to_props(prop)} />"
80
+ end
81
+
82
+ # Creates a stylesheet link tag.
83
+ #
84
+ # path - the href of the link tag
85
+ #
86
+ # prop - a hash of link tag attributes.
87
+ #
88
+ # => Defaults to :rel=>'stylesheet', :type=>'text/css', :media=>'all'
89
+ def stylesheet(path, prop={})
90
+ #<link rel="stylesheet" type="text/css" media="all" href="/css/style.css" />
91
+ path = timestamp_path(path)
92
+ prop[:rel] = 'stylesheet' if prop[:rel].nil?
93
+ prop[:type] = 'text/css' if prop[:type].nil?
94
+ prop[:media] = 'all' if prop[:media].nil?
95
+ "<link #{hash_to_props(prop)} href=\"#{path}\" />"
96
+ end
97
+
98
+ # Creates a link tag for feeds.
99
+ #
100
+ # opt - a hash of options which are passed to url(opt)
101
+ #
102
+ # prop - a hash of link tag attributes.
103
+ #
104
+ # => Example: :rel=>'alternate', :type=>'application/rss+', :media=>'all'
105
+ def feed(opt={}, prop={})
106
+ "<link #{hash_to_props(prop)} href=\"#{url(opt)}\" />"
107
+ end
108
+
109
+ # Creates a script tag.
110
+ #
111
+ # path - the src of the javascript tag
112
+ #
113
+ # prop - a hash of script tag attributes.
114
+ #
115
+ # => Defaults to: :type=>'text/javascript'
116
+ def javascript(path, prop={})
117
+ path = timestamp_path(path)
118
+ prop[:type] = 'text/javascript' if prop[:type].nil?
119
+ "<script #{hash_to_props(prop)} src=\"#{path}\"></script>"
120
+ end
121
+
122
+ # Creates metatags
123
+ #
124
+ # retuns a differnt metatag for each key/value added to @view[:meta] hash. See Doozer::Controller#meta for adding examples.
125
+ def metatags
126
+ #loop all metatags here...
127
+ out=[]
128
+ @view[:meta].each{ | key, value |
129
+ out.push("""<meta name=\"#{key.to_s}\" content=\"#{h(value)}\" />
130
+ """)
131
+ }
132
+ out.join("")
133
+ end
134
+
135
+ # Creates an authtoken form element
136
+ #
137
+ # By default, all post requests expect this value to be present unless overrided with Doozer::Controller#after_initialize
138
+ #
139
+ # You can customize the elemement id by passing arg[:id] to the method.
140
+ #
141
+ # The value contains an checksum of the app_name and cookie sid
142
+ def authtoken(args={})
143
+ id = args[:id] if args[:id]
144
+ "<input type=\"hidden\" id=\"#{id}_authtoken\" name=\"_authtoken\" value=\"#{generate_authtoken(@request.cookies['sid'])}\" />"
145
+ end
146
+
147
+ # Turns a hash of key/value pairs in to a key1="value1" key2="value2" key3="value3"
148
+ def hash_to_props(opt={})
149
+ props=[]
150
+ opt.each { | key, value |
151
+ props.push("#{key.to_s}=\"#{value}\"")
152
+ }
153
+ return " #{props.join(" ")}" if props.length > 0
154
+ return ""
155
+ end
156
+
157
+ # Turns a hash of key/value pairs in querystring like key1=value%201&key2=value2&key3=value3
158
+ #
159
+ # All values are CGI.escaped for output
160
+ def hash_to_qs(opt={})
161
+ props=[]
162
+ opt.each { | key, value |
163
+ props.push("#{key.to_s}=#{CGI::escape(value.to_s)}")
164
+ }
165
+ props.join("&")
166
+ end
167
+
168
+ # Safe encodes a string by entity encodes all less then and greater then signs
169
+ #
170
+ def h(s)
171
+ s.gsub!(/</,'&lt;')
172
+ s.gsub!(/>/,'&gt;')
173
+ return s
174
+ end
175
+
176
+ # Returns the base url configured in app.yml
177
+ #
178
+ def base_url
179
+ Doozer::Configs.base_url
180
+ end
181
+
182
+ # Returns the env setting the application was loaded under (:development, :deployment, or :test)
183
+ #
184
+ def rack_env
185
+ Doozer::Configs.rack_env
186
+ end
187
+
188
+ # Returns the app name configured in app.yml
189
+ #
190
+ def app_name
191
+ Doozer::Configs.app_name
192
+ end
193
+
194
+ # Returns the app path the application was loaded in. This defaults to the path all scripts were executed from. In general, this is the root of your project directory unless specified otherwise.
195
+ #
196
+ def app_path
197
+ Doozer::Configs.app_path
198
+ end
199
+
200
+ # Returns the ip address of the server
201
+ #
202
+ # Automatically accounts for proxied requests and returns HTTP_X_FORWARDED_FOR if present.
203
+ def ip
204
+ if addr = @env['HTTP_X_FORWARDED_FOR']
205
+ addr.split(',').last.strip
206
+ else
207
+ @env['REMOTE_ADDR']
208
+ end
209
+ end
210
+
211
+ # Returns the domain name of the request
212
+ #
213
+ def server_name
214
+ @env['SERVER_NAME']
215
+ end
216
+
217
+ # Returns the request path
218
+ #
219
+ def path
220
+ @env['REQUEST_PATH']
221
+ end
222
+
223
+ # Test if this person has a session with keys in it...
224
+ def session?
225
+ @session.empty?
226
+ end
227
+
228
+ private
229
+ def timestamp_path(path)
230
+ # p Doozer::Configs.rack_env
231
+ return path if Doozer::Configs.rack_env == :deployment
232
+ if path.index('?').nil?
233
+ path = "#{path}?#{@bust_key}"
234
+ else
235
+ path = "#{path}&#{@bust_key}"
236
+ end
237
+ end
238
+
239
+ ## check to see if form authtoken matches the one expected
240
+ ## phrase defaults to 'sid' which the default used for form authtokens
241
+ def authtoken_matches?(token, phrase=nil)
242
+ phrase = @request.cookies['sid'] if phrase.nil?
243
+ token == generate_authtoken(phrase)
244
+ end
245
+
246
+ def generate_authtoken(phrase)
247
+ Digest::SHA1.hexdigest("--#{app_name}--#{phrase}--")
248
+ end
249
+
250
+ end
251
+ end