rango 0.2.4.1 → 0.2.5.1

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.
data/CHANGELOG CHANGED
@@ -84,3 +84,13 @@
84
84
  * Ripple support in stack generator
85
85
  * Removed Erubis support, since it doesn't support <%= block(&block) %> so it's useless for us
86
86
  * Specs are green again
87
+
88
+ = Version 0.2.5
89
+ * Conventional rendering mixin for high-level rendering methods like autorender
90
+ * Added RESTController class as a base class for REST controllers
91
+ * Added CRUDMixin with controller CRUD methods
92
+ * UrlHelper#url can work not just as url(:post, @post.id) but also as url(:post, @post)
93
+ * Action args mixin doesn't raise argument error if there are some splat or block arguments
94
+ * Template caching
95
+ * Fixed gemspec to find executables
96
+ * First simple MIME support
@@ -95,7 +95,9 @@ module Rango
95
95
  if (300..399).include?(status)
96
96
  exception = Redirection.new(absolute_uri(location))
97
97
  exception.status = status
98
- exception.headers["Set-Cookie"] = response["Set-Cookie"] # otherwise it don't save cookies
98
+ if response["Set-Cookie"]
99
+ exception.headers["Set-Cookie"] = response["Set-Cookie"] # otherwise it don't save cookies
100
+ end
99
101
  block.call(exception) unless block.nil?
100
102
  raise exception
101
103
  else
@@ -23,6 +23,12 @@ class String
23
23
  return self if self !~ /_/ && self =~ /[A-Z]+.*/
24
24
  split('_').map{|e| e.capitalize}.join
25
25
  end
26
+
27
+ # TODO: this certainly isn't the way to go,
28
+ # but we need to get & refactor extlib at first
29
+ def pluralize
30
+ "#{self}s"
31
+ end
26
32
  end
27
33
 
28
34
  class Hash
@@ -21,16 +21,8 @@ module Rango
21
21
  view = self.method(action)
22
22
  parameters = view.parameters.map! { |type, name| [type, name.to_s] }
23
23
  names = parameters.map { |type, name| name }
24
- types = parameters.map { |type, name| type }
25
24
  required = parameters.map { |type, name| name if type.eql?(:req) }.compact
26
25
 
27
- # validate types
28
- if types.include?(:rest)
29
- raise ArgumentError, "View can't have splat argument. Use just this: def #{action}(#{names[0..-2].join(", ")})"
30
- elsif types.include?(:block)
31
- raise ArgumentError, "View can't have block argument. Use just this: def #{action}(#{names[0..-2].join(", ")})"
32
- end
33
-
34
26
  # validate names
35
27
  unless (extra_keys = required - self.params.keys).empty?
36
28
  raise ArgumentError, "Following keys aren't available in params: #{extra_keys.inspect}\nAvailable keys: #{self.params.keys.inspect}"
@@ -0,0 +1,65 @@
1
+ # encoding: utf-8
2
+
3
+ # Use with explicit or implicit rendering mixin
4
+ module Rango
5
+ module ConventionalRendering
6
+ def self.template_dirname=(template_dirname)
7
+ @@template_dirname = template_dirname
8
+ end
9
+
10
+ def self.template_dirname
11
+ @@template_dirname
12
+ rescue NameError
13
+ name = self.class.name
14
+ constant = name.gsub("::", "/")
15
+ dirname = constant.camel_case
16
+ @@template_dirname = dirname
17
+ end
18
+
19
+ def template_dirname
20
+ self.class.template_dirname
21
+ end
22
+
23
+ # @example
24
+ # def template_basename
25
+ # case request["router.action"]
26
+ # when "show"
27
+ # self.class.name.singularize
28
+ # when "index"
29
+ # else
30
+ # end
31
+ # end
32
+ #
33
+ # @api plugin
34
+ def template_basename
35
+ request["router.action"]
36
+ end
37
+
38
+ def template_path
39
+ File.join(template_dirname, template_basename)
40
+ end
41
+
42
+ def render_relative(template, context = nil)
43
+ if context
44
+ super File.join(template_dirname, template), context
45
+ else
46
+ super File.join(template_dirname, template)
47
+ end
48
+ end
49
+
50
+ def autorender(context = nil)
51
+ if context
52
+ render_relative template_basename, context
53
+ else
54
+ render_relative template_basename
55
+ end
56
+ end
57
+
58
+ def display(object)
59
+ autorender
60
+ rescue TemplateNotFound
61
+ callback = self.formats[request.action]
62
+ callback.call
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,51 @@
1
+ # encoding: utf-8
2
+
3
+ module CRUDMixin
4
+ def index(&block)
5
+ raise ArgumentError, "You have to provide a block" if block.nil?
6
+ set_context_value(collection_name, block.call)
7
+ autorender
8
+ end
9
+
10
+ def show(&block)
11
+ raise ArgumentError, "You have to provide a block" if block.nil?
12
+ set_context_value(collection_name, block.call)
13
+ autorender
14
+ end
15
+
16
+ def new(&block)
17
+ raise ArgumentError, "You have to provide a block" if block.nil?
18
+ set_context_value(collection_name, block.call)
19
+ autorender
20
+ end
21
+
22
+ def edit(&block)
23
+ raise ArgumentError, "You have to provide a block" if block.nil?
24
+ set_context_value(collection_name, block.call)
25
+ autorender
26
+ end
27
+
28
+ def create(notice = "Created successfully", error = "Can't create", &block)
29
+ raise ArgumentError, "You have to provide a block" if block.nil?
30
+ object = block.call
31
+ if object.save
32
+ message[:notice] = notice
33
+ redirect url(named_route, object)
34
+ else
35
+ message[:error] = error
36
+ render_relative "show"
37
+ end
38
+ end
39
+
40
+ def update(notice = "Updated successfully", error = "Can't update", &block)
41
+ raise ArgumentError, "You have to provide a block" if block.nil?
42
+ object = block.call
43
+ if object.save
44
+ message[:notice] = notice
45
+ redirect url(named_route, object)
46
+ else
47
+ message[:error] = error
48
+ render_relative "show"
49
+ end
50
+ end
51
+ end
@@ -4,56 +4,55 @@ require "rango/mixins/render"
4
4
 
5
5
  module Rango
6
6
  module FormatMixin
7
- def self.extended
7
+ MIME_TYPES = Rack::Mime::MIME_TYPES
8
+ def self.included(controller)
9
+ controller.class_eval do
10
+ extend ClassMethods
11
+ extend Module.new {
12
+ def inherited(subclass)
13
+ subclass.formats = self.formats
14
+ end
15
+ }
16
+ end
8
17
  end
9
18
 
10
- def inherited
19
+ def initialize(*args)
20
+ super(*args)
21
+ set_content_type
11
22
  end
12
23
 
13
- attr_writer :format
14
- def formats
15
- @formats ||= Hash.new { |hash, format| hash[:html] if hash.has_key?(:html) }
24
+ def set_content_type # rango::controller
25
+ # accept ...
16
26
  end
17
-
18
- # format(:json) do |object|
19
- # object.to_json
20
- # end
21
- def format(format, &block)
22
- self.formats[:format] = block
23
- end
24
- end
25
- module StackRendering
26
- include Rango::RenderMixin
27
- def template_dirname
28
- self.class.name.gsub("::", "/").camel_case
29
- end
30
-
31
- def template_basename
32
- request["router.action"]
33
- end
34
-
35
- #def template_basename
36
- # case request["router.action"]
37
- # when "show"
38
- # self.class.name.singularize
39
- # when "index"
40
- # else
41
- # end
42
- #end
43
-
44
- def template_path
45
- File.join(template_dirname, template_basename)
27
+ def set_content_type
28
+ super
29
+ unless headers["Content-Type"]
30
+ format = request.router_params[:format]
31
+ unless format.nil?
32
+ mime = self.class::MIME_TYPES[format]
33
+ headers["Content-Type"] = mime
34
+ end
35
+ end
46
36
  end
47
37
 
48
- def render(context = Hash.new)
49
- super(self.template_path, self.scope, self.context.merge!(context))
50
- end
38
+ module ClassMethods
39
+ attr_writer :format
40
+ def formats
41
+ @formats ||= Hash.new do |hash, format|
42
+ raise BadRequest, "Unsupported format"
43
+ end
44
+ end
51
45
 
52
- def display(object)
53
- render
54
- rescue TemplateNotFound
55
- callback = self.formats[request.action]
56
- callback.call
46
+ # format(:json) do |object|
47
+ # object.to_json
48
+ # end
49
+ def format(format = nil, &block)
50
+ if format
51
+ self.formats[:format] = block
52
+ else
53
+ self.formats.default_proc = block
54
+ end
55
+ end
57
56
  end
58
57
  end
59
58
 
@@ -89,6 +88,18 @@ module Rango
89
88
  def context
90
89
  @context ||= {request: self.request}
91
90
  end
91
+
92
+ def get_context_value(key)
93
+ @context[key]
94
+ end
95
+
96
+ def set_context_value(key, value)
97
+ @context[key] = value
98
+ end
99
+
100
+ def context_keys
101
+ @context.keys
102
+ end
92
103
  end
93
104
 
94
105
  module ImplicitRendering
@@ -100,5 +111,19 @@ module Rango
100
111
  def render(template) # so you can't specify context
101
112
  super template, self.scope
102
113
  end
114
+
115
+ def get_context_value(key)
116
+ instance_variable_get("@#{key}")
117
+ end
118
+
119
+ def set_context_value(key, value)
120
+ instance_variable_set("@#{key}", value)
121
+ end
122
+
123
+ def context_keys
124
+ instance_variables.map do |name|
125
+ name[1..-1].to_sym
126
+ end
127
+ end
103
128
  end
104
129
  end
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ require "rango/controller"
4
+ require "rango/mixins/crud"
5
+ require "rango/mixins/conventional_rendering"
6
+
7
+ module Rango
8
+ class RESTController < Controller
9
+ include CRUDMixin
10
+ include ConventionalRendering
11
+ def self.object_name=(object_name)
12
+ @@object_name = object_name
13
+ end
14
+
15
+ def self.object_name
16
+ @@object_name
17
+ rescue NameError
18
+ @@object_name = begin
19
+ name = self.class.name
20
+ name.split("::").last.snake_case
21
+ end
22
+ end
23
+
24
+ # @api plugin
25
+ def object_name
26
+ self.class.object_name
27
+ end
28
+
29
+ def collection_name
30
+ @@collection_name ||= @@object_name.to_s.pluralize
31
+ end
32
+
33
+ def self.named_route=(named_route)
34
+ @@named_route = named_route
35
+ end
36
+
37
+ def self.named_route
38
+ @@named_route
39
+ rescue NameError
40
+ @@named_route = begin
41
+ name = self.class.name
42
+ name.split("::").last.snake_case
43
+ end
44
+ end
45
+
46
+ def named_route
47
+ self.class.named_route
48
+ end
49
+ end
50
+ end
@@ -8,14 +8,46 @@ end
8
8
 
9
9
  Rango::Router.implement(:usher) do |env|
10
10
  # when usher routes to the default app, then usher.params is nil
11
- env["rango.router.params"] = env["usher.params"] || Hash.new
11
+ env["rango.router.params"] = env["usher.params"] || Hash.new # TODO: nil
12
12
  end
13
13
 
14
14
  module Rango
15
15
  module UrlHelper
16
16
  # url(:login)
17
17
  def url(*args)
18
- Rango::Router.app.router.generator.generate(*args)
18
+ generator = Rango::Router.app.router.generator
19
+ route_name = args.shift
20
+ route = generator.usher.named_routes[route_name]
21
+ raise "No route found" if route.nil? # TODO: add RouteNotFound to usher and use it here as well
22
+ if args.empty?
23
+ generator.generate(route_name) # TODO: usher should probably have path.to_url
24
+ else
25
+ alts = route.paths.map(&:dynamic_keys) # one route can have multiple paths as /:id or /:id.:format
26
+ keys = alts.first
27
+ # FIXME: take a look at other alts as well !!!!
28
+ # keys = alts.find.with_index { |item, index| }
29
+
30
+ # TODO: optional args
31
+ keys_generator = keys.each
32
+ args_generator = args.each
33
+ opts = Hash.new
34
+
35
+ keys.length.times do |index|
36
+ key = keys_generator.next
37
+ arg = args_generator.next
38
+ if arg.respond_to?(key) # post instance
39
+ opts[key] = arg.send(key)
40
+ else # it's already a slug
41
+ opts[key] = arg
42
+ end
43
+ end
44
+
45
+ generator.generate(route_name, opts)
46
+ end
19
47
  end
20
48
  end
21
49
  end
50
+
51
+
52
+ # route = Rango::Router.app.router.generator.usher.named_routes[:admin_edit_sticker]
53
+ # p route.paths.map(&:dynamic_keys)
@@ -28,7 +28,12 @@ module Rango
28
28
  # @since 0.0.2
29
29
  def initialize(path, scope = Object.new)
30
30
  self.path = path#[scope.class.template_prefix.chomp("/"), template].join("/")
31
- self.scope = scope.extend(TemplateHelpers)
31
+ self.scope = scope
32
+ self.scope.extend(TemplateHelpers)
33
+ # this enables template caching
34
+ unless Rango.development?
35
+ self.scope.extend(Tilt::CompileSite)
36
+ end
32
37
  self.scope.template = self
33
38
  end
34
39
 
data/lib/rango/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Rango
4
- VERSION = "0.2.4.1"
4
+ VERSION = "0.2.5.1"
5
5
  end
data/rango.gemspec CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
18
18
  # files
19
19
  s.files = `git ls-files`.split("\n")
20
20
 
21
- Dir["bin/*"].map(&File.method(:basename))
21
+ s.executables = Dir["bin/*"].map(&File.method(:basename))
22
22
  s.default_executable = "rango"
23
23
  s.require_paths = ["lib"]
24
24
 
@@ -19,10 +19,12 @@ describe Rango::ActionArgsMixin do
19
19
  "#{post} - #{msg}"
20
20
  end
21
21
 
22
- def view_with_a_splat(*args)
22
+ def view_with_a_splat(id, *args)
23
+ id
23
24
  end
24
25
 
25
- def view_with_a_block(&block)
26
+ def view_with_a_block(id, &block)
27
+ id
26
28
  end
27
29
  end
28
30
 
@@ -31,14 +33,16 @@ describe Rango::ActionArgsMixin do
31
33
  env.merge("rango.controller.action" => action)
32
34
  end
33
35
 
34
- it "should raise argument error if there is a splat argument" do
35
- env = env_for_action(:view_with_a_splat)
36
- -> { controller.call(env) }.should raise_error(ArgumentError)
36
+ it "should ignore splat arguments" do
37
+ env = env_for_action(:view_with_a_splat, "/?id=12")
38
+ status, headers, body = controller.call(env)
39
+ body.should eql(["12"])
37
40
  end
38
41
 
39
- it "should raise argument error if there is a block argument" do
40
- env = env_for_action(:view_with_a_block)
41
- -> { controller.call(env) }.should raise_error(ArgumentError)
42
+ it "should ignore block arguments" do
43
+ env = env_for_action(:view_with_a_block, "/?id=12")
44
+ status, headers, body = controller.call(env)
45
+ body.should eql(["12"])
42
46
  end
43
47
 
44
48
  it "should raise argument error if there are arguments which doesn't match any key in params" do
@@ -54,7 +58,6 @@ describe Rango::ActionArgsMixin do
54
58
 
55
59
  it "should call a view with arguments matching params[argument]" do
56
60
  env = env_for_action(:show, "/?id=12&msg=hi") # nevadi ze je tam toho vic
57
- instance = controller.new(env)
58
61
  status, headers, body = controller.call(env)
59
62
  body.should eql(["12"])
60
63
  end
File without changes
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative "../spec_helper"
4
+
5
+ require "rack/mock"
6
+ require "rango/rest_controller"
7
+
8
+ class TestRestController < Rango::RESTController
9
+ end
10
+
11
+ describe Rango::RESTController do
12
+ before(:each) do
13
+ env = Rack::MockRequest.env_for("/")
14
+ @controller = TestRestController.new(env)
15
+ end
16
+ end
data/spec/rango_spec.rb CHANGED
@@ -5,14 +5,15 @@ require "rango"
5
5
 
6
6
 
7
7
  describe Rango do
8
- it "should has logger" do
9
- #Rango.logger.should respond_to?(:debug)
10
- #Rango.logger.should respond_to?(:info)
11
- #Rango.logger.should respond_to?(:warn)
12
- #Rango.logger.should respond_to?(:error)
13
- #Rango.logger.should respond_to?(:fatal)
8
+ it "should have logger" do
9
+ Rango.logger.should respond_to?(:debug)
10
+ Rango.logger.should respond_to?(:info)
11
+ Rango.logger.should respond_to?(:warn)
12
+ Rango.logger.should respond_to?(:error)
13
+ Rango.logger.should respond_to?(:fatal)
14
14
  end
15
15
 
16
+ # what about logger vs. extlib logger (fatal!)
16
17
  describe ".boot" do
17
18
  # TODO
18
19
  end
@@ -43,6 +43,7 @@ gem "rack-router"#, git: "git://github.com/carllerche/rack-router.git"
43
43
  gem "tilt"#, git: "git://github.com/rtomayko/tilt.git"
44
44
  gem "haml"#, git: "git://github.com/nex3/haml.git"
45
45
  gem "helpers"#, git: "git://github.com/botanicus/helpers.git"
46
+ gem "formidable"#, git: "git://github.com/botanicus/formidable.git"
46
47
  gem "pupu"#, git: "git://github.com/botanicus/pupu.git"
47
48
  gem "media-path"#, git: "git://github.com/botanicus/media-path.git" # for asset helpers
48
49
 
@@ -96,7 +97,7 @@ end
96
97
  group(:test, :cucumber) do
97
98
  gem "rspec"#, git: "git://github.com/dchelimsky/rspec.git"
98
99
  gem "rack-test", require: "rack/test"#, git: "git://github.com/brynary/rack-test.git"
99
- gem "webrat"#, git: "git://github.com/brynary/webrat.git"
100
+ gem "capybara"#, git: "git://github.com/jnicklas/capybara.git"
100
101
  end
101
102
 
102
103
  group(:cucumber) do
@@ -13,5 +13,16 @@ require "multigiri/minify"
13
13
  Rango.after_boot(:rackup) do
14
14
  <%= @name.camel_case %>.rackup do
15
15
  use Rango::Middlewares::Basic
16
+
17
+ use Multigiri::HTML do
18
+ use Multigiri::HTML5::Forms
19
+ use Multigiri::HTML5::Hidden
20
+ use Multigiri::EmailObfuscator
21
+ # use Multigiri::GoogleAnalytics, :my_tracking_code
22
+ use Multigiri::DefaultAttributes
23
+ if Rango.development?
24
+ use Multigiri::LinkChecker, SimpleLogger::Logger.new("log/links.log")
25
+ end
26
+ end
16
27
  end
17
28
  end
metadata CHANGED
@@ -5,16 +5,16 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 2
8
- - 4
8
+ - 5
9
9
  - 1
10
- version: 0.2.4.1
10
+ version: 0.2.5.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - "Jakub \xC5\xA0\xC5\xA5astn\xC3\xBD aka Botanicus"
14
14
  autorequire:
15
15
  bindir: bin
16
16
  cert_chain:
17
- date: 2010-03-23 00:00:00 +00:00
17
+ date: 2010-05-08 00:00:00 +01:00
18
18
  default_executable: rango
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -47,8 +47,8 @@ dependencies:
47
47
  version_requirements: *id002
48
48
  description: ""
49
49
  email: stastny@101ideas.cz
50
- executables: []
51
-
50
+ executables:
51
+ - rango
52
52
  extensions: []
53
53
 
54
54
  extra_rdoc_files: []
@@ -96,6 +96,8 @@ files:
96
96
  - lib/rango/mini.rb
97
97
  - lib/rango/mini_render.rb
98
98
  - lib/rango/mixins/action_args.rb
99
+ - lib/rango/mixins/conventional_rendering.rb
100
+ - lib/rango/mixins/crud.rb
99
101
  - lib/rango/mixins/filters.rb
100
102
  - lib/rango/mixins/logger.rb
101
103
  - lib/rango/mixins/message.rb
@@ -114,6 +116,7 @@ files:
114
116
  - lib/rango/rack/middlewares/encoding.rb
115
117
  - lib/rango/rack/middlewares/static.rb
116
118
  - lib/rango/rack/request.rb
119
+ - lib/rango/rest_controller.rb
117
120
  - lib/rango/router.rb
118
121
  - lib/rango/router/adapters/crudtree.rb
119
122
  - lib/rango/router/adapters/rack_mount.rb
@@ -156,6 +159,7 @@ files:
156
159
  - spec/rango/mini_spec.rb
157
160
  - spec/rango/mixins/action_args_spec.rb
158
161
  - spec/rango/mixins/chainable_spec.rb
162
+ - spec/rango/mixins/conventional_rendering_spec.rb
159
163
  - spec/rango/mixins/filters_spec.rb
160
164
  - spec/rango/mixins/http_caching_spec.rb
161
165
  - spec/rango/mixins/logger_spec.rb
@@ -169,6 +173,7 @@ files:
169
173
  - spec/rango/rack/middlewares/encoding_spec.rb
170
174
  - spec/rango/rack/middlewares/static_spec.rb
171
175
  - spec/rango/rack/request_spec.rb
176
+ - spec/rango/rest_controller_spec.rb
172
177
  - spec/rango/router/adapters/crudtree_spec.rb
173
178
  - spec/rango/router/adapters/rack_mount_spec.rb
174
179
  - spec/rango/router/adapters/urlmap_spec.rb
@@ -276,13 +281,14 @@ has_rdoc: true
276
281
  homepage: http://github.com/botanicus/rango
277
282
  licenses: []
278
283
 
279
- post_install_message: "[\e[32mVersion 0.2.4\e[0m] Removed all helpers, if you need some, use http://github.com/botanicus/helpers\n\
280
- [\e[32mVersion 0.2.4\e[0m] [FEATURE] Added rango/mailer with mail helper for sending e-mails\n\
281
- [\e[32mVersion 0.2.4\e[0m] Rango.root & Rango.media_path are now instances of Pathname rather than String\n\
282
- [\e[32mVersion 0.2.4\e[0m] rango/environments are no longer optional\n\
283
- [\e[32mVersion 0.2.4\e[0m] Ripple support in stack generator\n\
284
- [\e[32mVersion 0.2.4\e[0m] Removed Erubis support, since it doesn't support <%= block(&block) %> so it's useless for us\n\
285
- [\e[32mVersion 0.2.4\e[0m] Specs are green again\n"
284
+ post_install_message: "[\e[32mVersion 0.2.5\e[0m] Conventional rendering mixin for high-level rendering methods like autorender\n\
285
+ [\e[32mVersion 0.2.5\e[0m] Added RESTController class as a base class for REST controllers\n\
286
+ [\e[32mVersion 0.2.5\e[0m] Added CRUDMixin with controller CRUD methods\n\
287
+ [\e[32mVersion 0.2.5\e[0m] UrlHelper#url can work not just as url(:post, @post.id) but also as url(:post, @post)\n\
288
+ [\e[32mVersion 0.2.5\e[0m] Action args mixin doesn't raise argument error if there are some splat or block arguments\n\
289
+ [\e[32mVersion 0.2.5\e[0m] Template caching\n\
290
+ [\e[32mVersion 0.2.5\e[0m] Fixed gemspec to find executables\n\
291
+ [\e[32mVersion 0.2.5\e[0m] First simple MIME support\n"
286
292
  rdoc_options: []
287
293
 
288
294
  require_paths: