utopia 0.9.61 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,12 @@
1
+
2
+ class NilClass
3
+ def maybe?
4
+ end
5
+ end
6
+
7
+ class Object
8
+ # A helper that allows you to avoid excessive number of i
9
+ def maybe?
10
+ yield self
11
+ end
12
+ end
@@ -15,7 +15,7 @@ class String
15
15
  end
16
16
 
17
17
  def to_title
18
- (" " + self).gsub(/[ \-_](.)/){" " + $1.upcase}.strip
18
+ self.gsub(/(^|[ \-_])(.)/){" " + $2.upcase}.strip
19
19
  end
20
20
 
21
21
  def to_snake
@@ -121,7 +121,14 @@ module Utopia
121
121
  return [200, {}, []]
122
122
  else
123
123
  response = Rack::Response.new
124
- node.process!(request, response)
124
+
125
+ attributes = {}
126
+
127
+ if request.controller
128
+ attributes = request.controller.to_hash
129
+ end
130
+
131
+ node.process!(request, response, attributes)
125
132
  return response.finish
126
133
  end
127
134
  else
@@ -21,10 +21,6 @@ module Utopia
21
21
  attr :tag
22
22
  end
23
23
 
24
- # Nodes typically represent XNODE files on the disk.
25
- # You can get a list of Links from a current directory. This comprises of all
26
- # files ending in ".xnode".
27
-
28
24
  class Transaction
29
25
  class State
30
26
  def initialize(tag, node)
@@ -37,6 +33,7 @@ module Utopia
37
33
  @attributes = tag.to_hash
38
34
 
39
35
  @content = nil
36
+ @deferred = []
40
37
  end
41
38
 
42
39
  attr :attributes
@@ -45,6 +42,14 @@ module Utopia
45
42
  attr :node
46
43
  attr :tags
47
44
 
45
+ attr :deferred
46
+
47
+ def defer(&block)
48
+ @deferred << block
49
+
50
+ Tag.closed("deferred", :id => @deferred.size - 1).to_html
51
+ end
52
+
48
53
  def [](key)
49
54
  @attributes[key.to_s]
50
55
  end
@@ -118,12 +123,12 @@ module Utopia
118
123
 
119
124
  attr :request
120
125
  attr :response
121
-
126
+
122
127
  # Begin tags represents a list from outer to inner most tag.
123
128
  # At any point in parsing xml, begin_tags is a list of the inner most tag,
124
129
  # then the next outer tag, etc. This list is used for doing dependent lookups.
125
130
  attr :begin_tags
126
-
131
+
127
132
  # End tags represents a list of execution order. This is the order that end tags
128
133
  # have appeared when evaluating nodes.
129
134
  attr :end_tags
@@ -218,21 +223,22 @@ module Utopia
218
223
  else
219
224
  current.tag_end(tag)
220
225
  end
221
-
226
+
222
227
  return nil
223
228
  end
224
229
 
225
230
  def render_node(node, attributes = {})
226
231
  state = State.new(attributes, node)
227
232
  @begin_tags << state
228
-
233
+
229
234
  return tag_end
230
235
  end
231
236
 
237
+ # Takes an instance of Tag
232
238
  def lookup(tag)
233
239
  result = tag
234
240
  node = nil
235
-
241
+
236
242
  @begin_tags.reverse_each do |state|
237
243
  result = state.lookup(result)
238
244
 
@@ -240,11 +246,11 @@ module Utopia
240
246
 
241
247
  return result if Node === result
242
248
  end
243
-
249
+
244
250
  @end_tags.reverse_each do |state|
245
251
  return state.node.lookup(result) if state.node.respond_to? :lookup
246
252
  end
247
-
253
+
248
254
  return nil
249
255
  end
250
256
 
@@ -293,7 +299,14 @@ module Utopia
293
299
  end
294
300
 
295
301
  def lookup(tag)
296
- return @controller.lookup_tag(tag.name, parent_path)
302
+ from_path = parent_path
303
+
304
+ # If the current node is called 'foo', we can't lookup 'foo' in the current directory or we will likely have infinite recursion.
305
+ if tag.name == @uri_path.basename
306
+ from_path = from_path.dirname
307
+ end
308
+
309
+ return @controller.lookup_tag(tag.name, from_path)
297
310
  end
298
311
 
299
312
  def parent_path
@@ -336,9 +349,9 @@ module Utopia
336
349
  transaction.parse_xml(xml_data)
337
350
  end
338
351
 
339
- def process!(request, response)
352
+ def process!(request, response, attributes = {})
340
353
  transaction = Transaction.new(request, response)
341
- response.write(transaction.render_node(self))
354
+ response.write(transaction.render_node(self, attributes))
342
355
  end
343
356
  end
344
357
 
@@ -20,22 +20,70 @@ module Utopia
20
20
  module Middleware
21
21
 
22
22
  class Controller
23
+ module Direct
24
+ def process!(path, request)
25
+ return nil unless path.dirname == self.class.uri_path
26
+
27
+ passthrough(path, request)
28
+ end
29
+ end
30
+
23
31
  CONTROLLER_RB = "controller.rb"
24
32
 
25
33
  class Variables
26
- def [](key)
27
- instance_variable_get("@#{key}")
34
+ def initialize
35
+ @controllers = [Object.new]
36
+ end
37
+
38
+ def << controller
39
+ @controllers << controller
40
+ end
41
+
42
+ def fetch(key)
43
+ @controllers.reverse_each do |controller|
44
+ if controller.instance_variables.include?(key)
45
+ return controller.instance_variable_get(key)
46
+ end
47
+ end
48
+
49
+ if block_given?
50
+ yield key
51
+ else
52
+ raise KeyError.new(key)
53
+ end
54
+ end
55
+
56
+ def to_hash
57
+ attributes = {}
58
+
59
+ @controllers.each do |controller|
60
+ controller.instance_variables.each do |name|
61
+ key = name[1..-1]
62
+
63
+ # Instance variables that start with an underscore are considered private and not exposed:
64
+ next if key.start_with?('_')
65
+
66
+ attributes[key] = controller.instance_variable_get(name)
67
+ end
68
+ end
69
+
70
+ return attributes
71
+ end
72
+
73
+ def [] key
74
+ fetch("@#{key}".to_sym) { nil }
28
75
  end
29
76
 
30
- def []=(key, value)
31
- instance_variable_set("@#{key}", value)
77
+ # Deprecated - to support old code:
78
+ def []= key, value
79
+ @controllers.first.instance_variable_set("@#{key}".to_sym, value)
32
80
  end
33
81
  end
34
82
 
35
83
  class Base
36
84
  def initialize(controller)
37
- @controller = controller
38
- @actions = {}
85
+ @_controller = controller
86
+ @_actions = {}
39
87
 
40
88
  methods.each do |method_name|
41
89
  next unless method_name.match(/on_(.*)$/)
@@ -43,12 +91,15 @@ module Utopia
43
91
  action($1.split("_")) do |path, request|
44
92
  # LOG.debug("Controller: #{method_name}")
45
93
  self.send(method_name, path, request)
94
+
95
+ # Don't pass the result back, instead use pass! or respond!
96
+ nil
46
97
  end
47
98
  end
48
99
  end
49
100
 
50
101
  def action(path, options = {}, &block)
51
- cur = @actions
102
+ cur = @_actions
52
103
 
53
104
  path.reverse.each do |name|
54
105
  cur = cur[name] ||= {}
@@ -58,7 +109,7 @@ module Utopia
58
109
  end
59
110
 
60
111
  def lookup(path)
61
- cur = @actions
112
+ cur = @_actions
62
113
 
63
114
  path.components.reverse.each do |name|
64
115
  cur = cur[name]
@@ -71,23 +122,49 @@ module Utopia
71
122
  end
72
123
  end
73
124
 
74
- # Given a request, call an associated action if one exists
125
+ # Given a request, call an associated action if one exists.
75
126
  def passthrough(path, request)
76
127
  action = lookup(path)
77
128
 
78
129
  if action
79
- return respond_with(action.call(path, request))
130
+ variables = request.controller
131
+ clone = self.dup
132
+
133
+ variables << clone
134
+
135
+ response = catch(:response) do
136
+ clone.instance_exec(path, request, &action)
137
+
138
+ # By default give nothing - i.e. keep on processing:
139
+ nil
140
+ end
141
+
142
+ if response
143
+ return clone.respond_with(*response)
144
+ end
80
145
  end
81
146
 
82
147
  return nil
83
148
  end
84
149
 
85
150
  def call(env)
86
- @controller.app.call(env)
151
+ @_controller.app.call(env)
152
+ end
153
+
154
+ def respond! (*args)
155
+ throw :response, args
87
156
  end
88
157
 
89
- def redirect(target, status = 302)
90
- {:redirect => target, :status => status}
158
+ def ignore!
159
+ throw :response, nil
160
+ end
161
+
162
+ def redirect! (target, status = 302)
163
+ respond! :redirect => target, :status => status
164
+ end
165
+
166
+ def fail!(error = :bad_request)
167
+ respond! error
91
168
  end
92
169
 
93
170
  def respond_with(*args)
@@ -133,8 +210,16 @@ module Utopia
133
210
  passthrough(path, request)
134
211
  end
135
212
 
213
+ def self.base_path
214
+ self.const_get(:BASE_PATH)
215
+ end
216
+
217
+ def self.uri_path
218
+ self.const_get(:URI_PATH)
219
+ end
220
+
136
221
  def self.require_local(path)
137
- require(File.join(const_get('BASE_PATH'), path))
222
+ require File.join(base_path, path)
138
223
  end
139
224
  end
140
225
 
@@ -179,8 +264,8 @@ module Utopia
179
264
 
180
265
  if File.exist?(controller_path)
181
266
  klass = Class.new(Base)
182
- klass.const_set('BASE_PATH', base_path)
183
- klass.const_set('URI_PATH', uri_path)
267
+ klass.const_set(:BASE_PATH, base_path)
268
+ klass.const_set(:URI_PATH, uri_path)
184
269
 
185
270
  $LOAD_PATH.unshift(base_path)
186
271
 
@@ -196,6 +281,7 @@ module Utopia
196
281
 
197
282
  def fetch_controllers(path)
198
283
  controllers = []
284
+
199
285
  path.ascend do |parent_path|
200
286
  controllers << lookup(parent_path)
201
287
  end
@@ -204,7 +290,7 @@ module Utopia
204
290
  end
205
291
 
206
292
  def call(env)
207
- env["utopia.controller"] ||= Variables.new
293
+ variables = (env["utopia.controller"] ||= Variables.new)
208
294
 
209
295
  request = Rack::Request.new(env)
210
296
 
@@ -32,15 +32,18 @@ module Utopia
32
32
  :text => [
33
33
  "html", "css", "js", "txt", "rtf", "xml", "pdf"
34
34
  ],
35
+ :fonts => [
36
+ "otf", ["eot", "application/vnd.ms-fontobject"], "ttf", "woff"
37
+ ],
35
38
  :archive => [
36
39
  "zip", "tar", "tgz", "tar.gz", "tar.bz2", ["dmg", "application/x-apple-diskimage"],
37
40
  ["torrent", "application/x-bittorrent"]
38
41
  ],
39
42
  :images => [
40
- "png", "gif", "jpeg", "tiff"
43
+ "png", "gif", "jpeg", "tiff", "svg"
41
44
  ],
42
45
  :default => [
43
- :media, :text, :archive, :images
46
+ :media, :text, :archive, :images, :fonts
44
47
  ]
45
48
  }
46
49
 
@@ -9,6 +9,8 @@ module Utopia
9
9
  class Path
10
10
  SEPARATOR = "/"
11
11
 
12
+ include Comparable
13
+
12
14
  def initialize(components)
13
15
  # To ensure we don't do anything stupid we freeze the components
14
16
  @components = components.dup.freeze
@@ -191,7 +193,7 @@ module Utopia
191
193
  end
192
194
  end
193
195
 
194
- def == other
196
+ def starts_with? other
195
197
  other.components.each_with_index do |part, index|
196
198
  return false if @components[index] != part
197
199
  end
@@ -11,7 +11,7 @@
11
11
  <?r end ?>
12
12
 
13
13
  <link rel="icon" type="image/png" href="/_static/icon.png" />
14
- <link rel="stylesheet" href="/_static/site.css" type="text/css" media="screen" charset="utf-8" />
14
+ <link rel="stylesheet" href="/_static/site.css" type="text/css" media="screen" />
15
15
  </head>
16
16
 
17
17
  <body>
@@ -5,6 +5,13 @@
5
5
  module Utopia
6
6
 
7
7
  class Tag
8
+ def self.closed(name, attributes = {})
9
+ tag = Tag.new(name, attributes)
10
+ tag.closed = true
11
+
12
+ return tag
13
+ end
14
+
8
15
  def initialize(name, attributes = {})
9
16
  @name = name
10
17
  @attributes = attributes
@@ -45,7 +52,11 @@ module Utopia
45
52
  buf.write "<#{name}"
46
53
 
47
54
  @attributes.each do |key, value|
48
- buf.write " #{key}=\"#{value}\""
55
+ if value
56
+ buf.write " #{key}=\"#{value}\""
57
+ else
58
+ buf.write " #{key}"
59
+ end
49
60
  end
50
61
 
51
62
  if terminate
@@ -0,0 +1,13 @@
1
+ # This file is part of the "Utopia Framework" project, and is released under the MIT license.
2
+ # Copyright 2010 Samuel Williams. All rights reserved.
3
+ # See <utopia.rb> for licensing details.
4
+
5
+ require 'utopia/tags'
6
+
7
+ Utopia::Tags.create("deferred") do |transaction, state|
8
+ id = state[:id].to_i
9
+
10
+ procedure = transaction.parent.deferred[id]
11
+
12
+ procedure.call(transaction, state)
13
+ end
@@ -6,6 +6,24 @@ require 'strscan'
6
6
 
7
7
  module Utopia
8
8
  class Trenni
9
+ # The output variable that will be used in templates:
10
+ OUT = '_out'
11
+
12
+ # Returns the output produced by calling the given block.
13
+ def self.capture(*args, &block)
14
+ out = eval(OUT, block.binding)
15
+ top = out.size
16
+
17
+ block.call *args
18
+
19
+ return out.pop(out.size - top).join
20
+ end
21
+
22
+ # Returns the buffer used for capturing output.
23
+ def self.buffer(binding)
24
+ eval(OUT, binding)
25
+ end
26
+
9
27
  class Buffer
10
28
  def initialize
11
29
  @parts = []
@@ -16,7 +34,7 @@ module Utopia
16
34
  def text(text)
17
35
  text = text.gsub('\\', '\\\\\\').gsub('@', '\\@')
18
36
 
19
- @parts << "_out << %q@#{text}@ ; "
37
+ @parts << "#{OUT} << %q@#{text}@ ; "
20
38
  end
21
39
 
22
40
  def expression(text)
@@ -24,11 +42,11 @@ module Utopia
24
42
  end
25
43
 
26
44
  def output(text)
27
- @parts << "_out << (#{text}) ; "
45
+ @parts << "#{OUT} << (#{text}) ; "
28
46
  end
29
47
 
30
48
  def code
31
- parts = ['_out = [] ; '] + @parts + ['_out.join']
49
+ parts = ["#{OUT} = [] ; "] + @parts + ["#{OUT}.join"]
32
50
 
33
51
  code = parts.join
34
52
  end
@@ -5,8 +5,8 @@
5
5
  module Utopia
6
6
  module VERSION
7
7
  MAJOR = 0
8
- MINOR = 9
9
- TINY = 61
8
+ MINOR = 10
9
+ TINY = 0
10
10
 
11
11
  STRING = [MAJOR, MINOR, TINY].join('.')
12
12
  end
@@ -26,7 +26,9 @@ module Utopia
26
26
 
27
27
  class Scanner < StringScanner
28
28
  CDATA = /[^<]+/m
29
- TAG_PARAMETER = /\s*([^\s=\/>]*)=((['"])(.*?)\3)/um
29
+ # Parse an attribute in the form of key="value" or key.
30
+ ATTRIBUTE_NAME = /\s*([^\s=\/>]+)/um
31
+ ATTRIBUTE_VALUE = /=((['"])(.*?)\2)/um
30
32
 
31
33
  def initialize(callback, string)
32
34
  @callback = callback
@@ -87,8 +89,13 @@ module Utopia
87
89
  end
88
90
 
89
91
  def scan_attributes
90
- while scan(TAG_PARAMETER)
91
- @callback.attribute(self[1], self[4])
92
+ while scan(ATTRIBUTE_NAME)
93
+ name = self[1]
94
+ if scan(ATTRIBUTE_VALUE)
95
+ @callback.attribute(name, self[3])
96
+ else
97
+ @callback.attribute(name, nil)
98
+ end
92
99
  end
93
100
  end
94
101
 
metadata CHANGED
@@ -1,96 +1,109 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: utopia
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 9
8
- - 61
9
- version: 0.9.61
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.10.0
5
+ prerelease:
10
6
  platform: ruby
11
- authors:
7
+ authors:
12
8
  - Samuel Williams
13
9
  autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
-
17
- date: 2012-06-16 00:00:00 +12:00
18
- default_executable: utopia
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
12
+ date: 2012-07-31 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
21
15
  name: mime-types
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
24
- requirements:
25
- - - ">="
26
- - !ruby/object:Gem::Version
27
- segments:
28
- - 0
29
- version: "0"
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
30
22
  type: :runtime
31
- version_requirements: *id001
32
- - !ruby/object:Gem::Dependency
33
- name: rack
34
23
  prerelease: false
35
- requirement: &id002 !ruby/object:Gem::Requirement
36
- requirements:
37
- - - ">="
38
- - !ruby/object:Gem::Version
39
- segments:
40
- - 0
41
- version: "0"
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rack
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
42
38
  type: :runtime
43
- version_requirements: *id002
44
- - !ruby/object:Gem::Dependency
45
- name: rack-cache
46
39
  prerelease: false
47
- requirement: &id003 !ruby/object:Gem::Requirement
48
- requirements:
49
- - - ">="
50
- - !ruby/object:Gem::Version
51
- segments:
52
- - 0
53
- version: "0"
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rack-cache
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
54
  type: :runtime
55
- version_requirements: *id003
56
- - !ruby/object:Gem::Dependency
57
- name: rack-contrib
58
55
  prerelease: false
59
- requirement: &id004 !ruby/object:Gem::Requirement
60
- requirements:
61
- - - ">="
62
- - !ruby/object:Gem::Version
63
- segments:
64
- - 0
65
- version: "0"
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rack-contrib
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
66
70
  type: :runtime
67
- version_requirements: *id004
68
- - !ruby/object:Gem::Dependency
69
- name: rmagick
70
71
  prerelease: false
71
- requirement: &id005 !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- segments:
76
- - 0
77
- version: "0"
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rmagick
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
78
86
  type: :runtime
79
- version_requirements: *id005
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
80
94
  description:
81
95
  email: samuel.williams@oriontransfer.co.nz
82
- executables:
96
+ executables:
83
97
  - utopia
84
98
  extensions: []
85
-
86
99
  extra_rdoc_files: []
87
-
88
- files:
100
+ files:
89
101
  - ext/utopia/xnode/fast_scanner/extconf.rb
90
102
  - ext/utopia/xnode/fast_scanner/parser.c
91
103
  - lib/utopia/extensions/array.rb
92
104
  - lib/utopia/extensions/date.rb
93
105
  - lib/utopia/extensions/hash.rb
106
+ - lib/utopia/extensions/maybe.rb
94
107
  - lib/utopia/extensions/rack.rb
95
108
  - lib/utopia/extensions/regexp.rb
96
109
  - lib/utopia/extensions/string.rb
@@ -130,6 +143,7 @@ files:
130
143
  - lib/utopia/setup.rb
131
144
  - lib/utopia/tag.rb
132
145
  - lib/utopia/tags/all.rb
146
+ - lib/utopia/tags/deferred.rb
133
147
  - lib/utopia/tags/env.rb
134
148
  - lib/utopia/tags/fortune.rb
135
149
  - lib/utopia/tags/gallery.rb
@@ -145,35 +159,29 @@ files:
145
159
  - lib/utopia/xnode.rb
146
160
  - lib/utopia.rb
147
161
  - bin/utopia
148
- has_rdoc: true
149
162
  homepage: http://www.oriontransfer.co.nz/software/utopia
150
163
  licenses: []
151
-
152
164
  post_install_message:
153
165
  rdoc_options: []
154
-
155
- require_paths:
166
+ require_paths:
156
167
  - lib
157
- required_ruby_version: !ruby/object:Gem::Requirement
158
- requirements:
159
- - - ">="
160
- - !ruby/object:Gem::Version
161
- segments:
162
- - 0
163
- version: "0"
164
- required_rubygems_version: !ruby/object:Gem::Requirement
165
- requirements:
166
- - - ">="
167
- - !ruby/object:Gem::Version
168
- segments:
169
- - 0
170
- version: "0"
168
+ required_ruby_version: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ required_rubygems_version: !ruby/object:Gem::Requirement
175
+ none: false
176
+ requirements:
177
+ - - ! '>='
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
171
180
  requirements: []
172
-
173
181
  rubyforge_project:
174
- rubygems_version: 1.3.6
182
+ rubygems_version: 1.8.23
175
183
  signing_key:
176
184
  specification_version: 3
177
185
  summary: Utopia is a framework for building websites.
178
186
  test_files: []
179
-
187
+ has_rdoc: