has_browser 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README +44 -0
- data/Rakefile +8 -0
- data/init.rb +4 -0
- data/lib/has_browser/version.rb +11 -0
- data/lib/has_browser.rb +45 -0
- data/tasks/gem.rake +55 -0
- data/tasks/test.rake +8 -0
- data/test/has_browser_test.rb +51 -0
- data/test/test_helper.rb +15 -0
- metadata +63 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 James Golick, Giraffesoft Inc.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
HasBrowser
|
2
|
+
==========
|
3
|
+
|
4
|
+
has_browser makes it possible to create simple, parameterized browser interfaces to your models. That is, given a set of parameters, return all the models that match.
|
5
|
+
|
6
|
+
== Usage
|
7
|
+
|
8
|
+
It's a simple plugin, with a simple syntax. Using the canonical blog example, let's imagine we want to create a browse interface to posts. We'd want the user to be able to browse by category, author, or tags, but not to be able to access any of the other finders on the Post model for obvious security reasons. To set up has_browser, we'd do something like this:
|
9
|
+
|
10
|
+
has_browser :category, :tags, :author
|
11
|
+
|
12
|
+
Then, assuming the has_finders are already written, the posts can be browsed as follows:
|
13
|
+
|
14
|
+
Post.browse(:category => 'Testing', :tags => 'activerecord', :author => 'james')
|
15
|
+
|
16
|
+
In that example, each of the finders requires an argument; has_browser also supports finders that don't. As long as the argumentless finder is present in the browse hash, it will be called:
|
17
|
+
|
18
|
+
has_browser :category, :tags, :author, :without_args => [:order_by_date, :order_by_number_of_comments]
|
19
|
+
|
20
|
+
Post.browse(:category => 'Testing', :tags => 'activerecord', :author => 'james', :order_by_number_of_comments => 'true')
|
21
|
+
|
22
|
+
Browse can also be called from association_proxies. For a multi-blog platform, we could easily restrict browsing of posts to the current blog:
|
23
|
+
|
24
|
+
@blog.posts.browse(:category => 'Testing', :tags => 'activerecord', :author => 'james', :order_by_number_of_comments => 'true')
|
25
|
+
|
26
|
+
Since has_browser returns the same proxy as has_finder, it is possible to further restrict the results of a browse by chaining finders after the browse call. With our blog, for example, we'd probably want to restrict browsing to published posts.
|
27
|
+
|
28
|
+
@blog.posts.browse(:category => 'Testing', :tags => 'activerecord', :author => 'james', :order_by_number_of_comments => 'true').published
|
29
|
+
|
30
|
+
Note: It is not possible to chain finders before the browse call.
|
31
|
+
|
32
|
+
Finally, like has_finder, has_browser is compatible with will_paginate out of the box.
|
33
|
+
|
34
|
+
== Releases & Development
|
35
|
+
|
36
|
+
has_browser will be released as a gem:
|
37
|
+
|
38
|
+
$ sudo gem install has_browser
|
39
|
+
|
40
|
+
development will continue at {github}[http://github.com/giraffesoft/has_browser]
|
41
|
+
|
42
|
+
== Credits & License
|
43
|
+
|
44
|
+
Copyright (c) 2008 {James Golick}[http://jamesgolick.com], {GiraffeSoft Inc.}[http://giraffesoft.ca], released under the {MIT License}[http://en.wikipedia.org/wiki/MIT_License]
|
data/Rakefile
ADDED
data/init.rb
ADDED
data/lib/has_browser.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
module HasBrowser
|
2
|
+
NAME = 'has_browser'
|
3
|
+
|
4
|
+
class InvalidFinder < ArgumentError; end
|
5
|
+
|
6
|
+
def self.included(receiver)
|
7
|
+
receiver.send :extend, ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def has_browser(*args)
|
12
|
+
extend BrowserMethods
|
13
|
+
class_inheritable_accessor :has_browser_allowed_finders
|
14
|
+
self.has_browser_allowed_finders = {}
|
15
|
+
|
16
|
+
has_browser_allowed_finders[:without_args] = args.extract_options![:without_args] || []
|
17
|
+
has_browser_allowed_finders[:with_args] = args
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module BrowserMethods
|
22
|
+
def browse(*args)
|
23
|
+
params = args.extract_options!.symbolize_keys
|
24
|
+
|
25
|
+
invalid_finders = params.keys.reject { |k| has_browser_allowed_finders.values.inject(&:+).include?(k) }
|
26
|
+
raise InvalidFinder.new(invalid_finders.join(', ').to_s) unless invalid_finders.empty?
|
27
|
+
|
28
|
+
params.inject(args.first || self) do |proxy, finder|
|
29
|
+
has_browser_allowed_finders[:with_args].include?(finder.first.to_sym) ? proxy.send(finder.first, finder.last) : proxy.send(finder.first)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module AssociationProxyMethods
|
35
|
+
def self.included(receiver)
|
36
|
+
receiver.class_eval do
|
37
|
+
alias_method_chain :method_missing, :has_browser
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def method_missing_with_has_browser(method, *args, &block)
|
42
|
+
method == :browse && proxy_reflection.klass.respond_to?(:has_browser_allowed_finders) ? proxy_reflection.klass.browse(self, args.extract_options!) : method_missing_without_has_browser(method, *args, &block)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/tasks/gem.rake
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'rake/gempackagetask'
|
2
|
+
|
3
|
+
task :clean => :clobber_package
|
4
|
+
|
5
|
+
spec = Gem::Specification.new do |s|
|
6
|
+
s.name = HasBrowser::NAME
|
7
|
+
s.version = HasBrowser::Version::STRING
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.summary =
|
10
|
+
s.description = "has_browser makes it possible to create simple, parameterized browser interfaces to your models."
|
11
|
+
s.author = "James Golick"
|
12
|
+
s.email = 'james@giraffesoft.ca'
|
13
|
+
s.homepage = 'http://jamesgolick.com/'
|
14
|
+
|
15
|
+
s.required_ruby_version = '>= 1.8.6'
|
16
|
+
|
17
|
+
s.files = %w(MIT-LICENSE README Rakefile init.rb) +
|
18
|
+
Dir.glob("{lib,test,tasks}/**/*")
|
19
|
+
|
20
|
+
s.require_path = "lib"
|
21
|
+
end
|
22
|
+
|
23
|
+
Rake::GemPackageTask.new(spec) do |p|
|
24
|
+
p.gem_spec = spec
|
25
|
+
end
|
26
|
+
|
27
|
+
task :tag_warn do
|
28
|
+
puts "*" * 40
|
29
|
+
puts "Don't forget to tag the release:"
|
30
|
+
puts " git tag -a v#{HasBrowser::Version::STRING}"
|
31
|
+
puts "*" * 40
|
32
|
+
end
|
33
|
+
task :gem => :tag_warn
|
34
|
+
|
35
|
+
task :compile do
|
36
|
+
end
|
37
|
+
|
38
|
+
namespace :gem do
|
39
|
+
namespace :upload do
|
40
|
+
desc 'Upload gems to rubyforge.org'
|
41
|
+
task :rubyforge => :gem do
|
42
|
+
sh 'rubyforge login'
|
43
|
+
sh "rubyforge add_release giraffesoft has_browser #{HasBrowser::Version::STRING} pkg/#{spec.full_name}.gem"
|
44
|
+
sh "rubyforge add_file giraffesoft has_browser #{HasBrowser::Version::STRING} pkg/#{spec.full_name}.gem"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
task :install => [:clobber, :compile, :package] do
|
50
|
+
sh "sudo gem install pkg/#{spec.full_name}.gem"
|
51
|
+
end
|
52
|
+
|
53
|
+
task :uninstall => :clobber do
|
54
|
+
sh "sudo gem uninstall #{spec.name}"
|
55
|
+
end
|
data/tasks/test.rake
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.dirname(__FILE__)+'/test_helper'
|
2
|
+
|
3
|
+
class HasBrowserTest < Test::Unit::TestCase
|
4
|
+
def test_should_call_appropriate_finders_when_somebody_browses_by_parameters
|
5
|
+
PhotoMock.expects(:title).with('something').returns(PhotoMock)
|
6
|
+
PhotoMock.expects(:description).with('lorem ipsum dolor').returns(PhotoMock)
|
7
|
+
PhotoMock.expects(:order_by_date).returns(PhotoMock)
|
8
|
+
|
9
|
+
PhotoMock.browse(:title => 'something', :description => 'lorem ipsum dolor', :order_by_date => 'true')
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_browsing_with_an_alternate_target
|
13
|
+
proxy_mock = mock
|
14
|
+
proxy_mock.expects(:title).with('something').returns(proxy_mock)
|
15
|
+
proxy_mock.expects(:description).with('lorem ipsum dolor').returns(proxy_mock)
|
16
|
+
proxy_mock.expects(:order_by_date).returns(proxy_mock)
|
17
|
+
|
18
|
+
PhotoMock.browse(proxy_mock, :title => 'something', :description => 'lorem ipsum dolor', :order_by_date => 'true')
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_association_proxy_finder_should_proxy_to_the_reflected_class_browse_method
|
22
|
+
proxy_mock = AssocProxyMock.new
|
23
|
+
proxy_mock.stubs(:proxy_reflection).returns(stub(:klass => PhotoMock))
|
24
|
+
|
25
|
+
PhotoMock.expects(:browse).with(proxy_mock, :title => 'something', :description => 'lorem ipsum dolor', :order_by_date => 'true')
|
26
|
+
|
27
|
+
proxy_mock.browse(:title => 'something', :description => 'lorem ipsum dolor', :order_by_date => 'true')
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_association_proxy_should_raise_if_browse_is_called_and_target_doesnt_have_a_browser
|
31
|
+
proxy_mock = AssocProxyMock.new
|
32
|
+
proxy_mock.stubs(:proxy_reflection).returns(stub(:klass => String))
|
33
|
+
|
34
|
+
assert_raise(NoMethodError) do
|
35
|
+
proxy_mock.browse({})
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_should_not_raise_when_keys_are_strings
|
40
|
+
PhotoMock.stubs(:title)
|
41
|
+
assert_nothing_raised do
|
42
|
+
PhotoMock.browse('title' => 'asdf')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_should_raise_invalid_finder_exception_if_somebody_tries_to_browse_by_a_finder_not_specified_in_the_browse_call
|
47
|
+
assert_raise(HasBrowser::InvalidFinder) do
|
48
|
+
PhotoMock.browse(:invalid => 'danger!')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "mocha"
|
3
|
+
require "activesupport"
|
4
|
+
require "test/unit"
|
5
|
+
require File.dirname(__FILE__)+"/../lib/has_browser"
|
6
|
+
|
7
|
+
class PhotoMock
|
8
|
+
include HasBrowser
|
9
|
+
|
10
|
+
has_browser :title, :description, :without_args => [:order_by_date, :order_by_relevance]
|
11
|
+
end
|
12
|
+
|
13
|
+
class AssocProxyMock
|
14
|
+
include HasBrowser::AssociationProxyMethods
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: has_browser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- James Golick
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-05-19 00:00:00 -04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: has_browser makes it possible to create simple, parameterized browser interfaces to your models.
|
17
|
+
email: james@giraffesoft.ca
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- MIT-LICENSE
|
26
|
+
- README
|
27
|
+
- Rakefile
|
28
|
+
- init.rb
|
29
|
+
- lib/has_browser
|
30
|
+
- lib/has_browser/version.rb
|
31
|
+
- lib/has_browser.rb
|
32
|
+
- test/has_browser_test.rb
|
33
|
+
- test/test_helper.rb
|
34
|
+
- tasks/gem.rake
|
35
|
+
- tasks/test.rake
|
36
|
+
has_rdoc: false
|
37
|
+
homepage: http://jamesgolick.com/
|
38
|
+
post_install_message:
|
39
|
+
rdoc_options: []
|
40
|
+
|
41
|
+
require_paths:
|
42
|
+
- lib
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.8.6
|
48
|
+
version:
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
55
|
+
requirements: []
|
56
|
+
|
57
|
+
rubyforge_project:
|
58
|
+
rubygems_version: 1.1.1
|
59
|
+
signing_key:
|
60
|
+
specification_version: 2
|
61
|
+
summary: has_browser makes it possible to create simple, parameterized browser interfaces to your models.
|
62
|
+
test_files: []
|
63
|
+
|