exposure 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ *.gem
2
+ *.gemspec
3
+ pkg
data/NOTES ADDED
@@ -0,0 +1,57 @@
1
+ TOC.
2
+ I. Installing
3
+ sudo gem install exposure
4
+ II. REST
5
+ III. Current Controller behavior with class methods
6
+ IV. Exposure
7
+ A. expose
8
+ B. Finders
9
+ C. Responders
10
+ D. Flashers
11
+ E. Callbacks
12
+
13
+ Controllers already have some configuration-like structure:
14
+ before_filter
15
+ after_filter
16
+ around_filter
17
+
18
+ skip_before_filter
19
+ skip_after_filter
20
+ skip_around_filter
21
+
22
+ verify
23
+ layout
24
+ filter_parameter_logging
25
+ rescue_from
26
+
27
+ We're adding
28
+ expose
29
+ find
30
+ response_for
31
+ flash_for
32
+
33
+ the following callbacks:
34
+ before_find
35
+ after_find
36
+ after_find_on_failure
37
+ after_find_on_success
38
+ before_assign
39
+ after_assign
40
+ before_save
41
+ after_save
42
+ after_save_on_failure
43
+ after_save_on_success
44
+ before_create
45
+ after_create_on_failure
46
+ after_create_on_success
47
+ before_update
48
+ after_update_on_failure
49
+ after_update_on_success
50
+ before_destroy
51
+ after_destroy_on_success
52
+ before_response
53
+ before_response_on_success
54
+ before_response_on_failure
55
+ and speciality access to these callbacks with
56
+ before
57
+ after
data/Rakefile CHANGED
@@ -1,23 +1,14 @@
1
1
  require 'rubygems'
2
- gem 'hoe', '>= 2.1.0'
3
- require 'hoe'
4
- require 'fileutils'
5
- require './lib/exposure'
6
-
7
- Hoe.plugin :newgem
8
- # Hoe.plugin :website
9
- # Hoe.plugin :cucumberfeatures
10
-
11
- # Generate all the Rake tasks
12
- # Run 'rake -T' to see list of generated tasks (from gem root directory)
13
- $hoe = Hoe.spec 'exposure' do
14
- self.developer 'Trek Glowacki', 'trek.glowacki@gmail.com'
15
- self.summary = 'exposed resources'
2
+ require 'rake'
3
+ require 'jeweler'
4
+
5
+ Jeweler::Tasks.new do |gemspec|
6
+ gemspec.name = 'exposure'
7
+ gemspec.summary = 'exposed resources'
8
+ gemspec.description = 'exposed resources'
9
+ gemspec.email = 'trek.glowacki@gmail.com'
10
+ gemspec.authors = ['Trek Glowacki']
16
11
  end
12
+ Jeweler::GemcutterTasks.new
17
13
 
18
- require 'newgem/tasks'
19
- Dir['tasks/**/*.rake'].each { |t| load t }
20
-
21
- # TODO - want other tests/tasks run by default? Add them to the list
22
- # remove_task :default
23
- # task :default => [:spec, :features]
14
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.7
@@ -0,0 +1,36 @@
1
+ module Exposure
2
+ module Building
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ base.send(:include, InstaneMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def build(name, options = {}, &block)
10
+ options[:with] ||= block
11
+ self.const_get(:Builders)[name] = options[:with]
12
+ end
13
+
14
+ def build_default_builder(member, nesting)
15
+ self::const_set(:DefaultBuilder, {
16
+ self.resource_name.intern => Proc.new { [:new, params[resource_name] ] }
17
+ })
18
+ end
19
+ end
20
+
21
+ module InstaneMethods
22
+ private
23
+ def custom_builder_for(resource_name)
24
+
25
+ end
26
+
27
+ def default_builder_for(resource_name)
28
+
29
+ end
30
+
31
+ def builder_for(resource_name)
32
+ custom_builder_for(resource_name) || default_builder_for(resource_name)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,53 @@
1
+ module Exposure
2
+ module Callbacks
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ base.send(:include, InstaneMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ # access point for creating and configuring before_ callbacks.
10
+ def before(trigger, *actions)
11
+ options = actions.extract_options!
12
+ actions.each do |action|
13
+ build_callback('before', trigger, action, options)
14
+ end
15
+ end
16
+
17
+ # access point for creating and configuring after_ callbacks.
18
+ def after(trigger, *actions)
19
+ options = actions.extract_options!
20
+ actions.each do |action|
21
+ build_callback('after', trigger, action, options)
22
+ end
23
+ end
24
+
25
+ # builds callbacks that adhere to the ActiveSupport::Callbacks interface
26
+ def build_callback(prefix, trigger, action, options) #:nodoc:
27
+ callback_name = "#{prefix}_#{trigger}"
28
+
29
+ if options[:on]
30
+ callback_name += "_on_#{options.delete(:on)}"
31
+ end
32
+
33
+ options[:if] ||= []
34
+
35
+ only_methods = options.delete(:only)
36
+ except_methods = options.delete(:except)
37
+
38
+ if only_methods
39
+ options[:if] << Proc.new {|c| only_methods.include?(c.action_name.intern) }
40
+ end
41
+
42
+ if except_methods
43
+ options[:if] << Proc.new {|c| !except_methods.include?(c.action_name.intern) }
44
+ end
45
+
46
+ self.send(callback_name, action, options)
47
+ end
48
+ end
49
+
50
+ module InstaneMethods
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,84 @@
1
+ module Exposure
2
+ module Finding
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ base.send(:include, InstaneMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ # find :person, :with => Proc.new { Person.find_by_permalink(params[:permalink]) }
10
+ # find :people, :with => Proc.new { Person.send(params[:scope]) }
11
+ # find :dogs, :with => :dogs_adopted_after_date
12
+ # find :dogs do
13
+ # Dog.all
14
+ # end
15
+ #
16
+ # valid options are
17
+ # :with
18
+ # :only (unimplemented)
19
+ # :except (unimplemented)
20
+ def find(name, options = {}, &block)
21
+ options[:with] ||= block
22
+ self.const_get(:Finders)[name] = options[:with]
23
+ end
24
+
25
+ def build_default_finders(member, nesting) #:nodoc:
26
+ finders = self::const_set(:DefaultFinders, {
27
+ self.resource_name.intern => Proc.new { [:find, params[:id] ] },
28
+ self.resources_name.intern => Proc.new { [:all] }
29
+ })
30
+
31
+ nesting.each do |association_name|
32
+ finders[association_name.to_s.singularize.to_sym] = Proc.new { [:find, params[:"#{association_name.to_s.singularize}_id"]] }
33
+ finders[association_name] = Proc.new { [ :all ] }
34
+ end
35
+ end
36
+ end
37
+
38
+ module InstaneMethods
39
+ private
40
+ def custom_finder_for(resource_name)
41
+ if finder = self.class::Finders[resource_name]
42
+ return finder
43
+ end
44
+ end
45
+
46
+ def default_finder_for(resource_name)
47
+ if finder = self.class::DefaultFinders[resource_name]
48
+ return finder
49
+ end
50
+ end
51
+
52
+ def finder_for(resource_name)
53
+ custom_finder_for(resource_name) || default_finder_for(resource_name)
54
+ end
55
+
56
+ def call_finder_chain(object, chain, use_associaiton = true)
57
+ links = chain.shift
58
+ return object unless links
59
+
60
+ message = finder_for(links[0])
61
+ association = links[1] if use_associaiton
62
+
63
+ case message
64
+ when Symbol
65
+ value = self.send(message)
66
+ when Proc
67
+ value = self.instance_eval(&message)
68
+ else
69
+ raise "invalid finder of #{message.inspect}"
70
+ end
71
+
72
+ if value.kind_of?(Array) && !value.respond_to?(:proxy_target)
73
+ if use_associaiton
74
+ call_finder_chain(object.send(association).send(*value), chain)
75
+ else
76
+ call_finder_chain(object.send(*value), chain)
77
+ end
78
+ else
79
+ call_finder_chain(value, chain)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,62 @@
1
+ module Exposure
2
+ module Flashing
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ base.send(:include, InstaneMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ # configure flash messages
10
+ # valid action names are
11
+ # :index :show :new :create :edit :update :destroy
12
+ # valid options are
13
+ # :on (optional)
14
+ # :success, :failure, :any
15
+ # default is :any
16
+ # :is (optional if block given)
17
+ # can be a Proc or method name as symbol.
18
+ def flash_for(action_name, options = {}, &block)
19
+ options[:is] ||= block
20
+
21
+ case options[:on]
22
+ when NilClass, :any
23
+ self.const_get(:FlashMessages)["#{action_name}.success.html"] = options[:is]
24
+ self.const_get(:FlashMessages)["#{action_name}.failure.html"] = options[:is]
25
+ when :success
26
+ self.const_get(:FlashMessages)["#{action_name}.success.html"] = options[:is]
27
+ when :failure
28
+ self.const_get(:FlashMessages)["#{action_name}.failure.html"] = options[:is]
29
+ end
30
+ end
31
+ end
32
+
33
+ module InstaneMethods
34
+ private
35
+ def custom_flash_for(action_name, action_status)
36
+ if flash_message = self.class::FlashMessages["#{action_name}.#{action_status}.html"]
37
+ case flash_message
38
+ when String
39
+ flash[:message] = flash_message
40
+ when Symbol
41
+ flash[:message] = self.send(flash_message)
42
+ when Proc
43
+ flash[:message] = self.instance_eval(&flash_message)
44
+ end
45
+ else
46
+ false
47
+ end
48
+ end
49
+
50
+ def default_flash_for(action_name, action_status)
51
+ if message_proc = self.class::DefaultFlashMessages["#{action_name}.#{action_status}.html"]
52
+ flash[:message] = self.instance_eval(&message_proc)
53
+ end
54
+ end
55
+
56
+ def flash_for(action_name, action_successful)
57
+ custom_flash_for(action_name, action_successful) || default_flash_for(action_name, action_successful)
58
+ end
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,80 @@
1
+ module Exposure
2
+ module Responding
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ base.send(:include, InstaneMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ # response_for :create, :on => :success, :is => { proc }
10
+ # response_for :show, :formats => [:html] do
11
+ # @resource.activated ? render('show') : render('next_steps')
12
+ # end
13
+ # response_for :new, :is => :new_foo_built
14
+ #
15
+ # valid action names are
16
+ # :index :show :new :create :edit :update :destroy
17
+ # valid options are
18
+ # :on (optional)
19
+ # :success, :failure, :any
20
+ # default is :any
21
+ # :is (option if block given)
22
+ # can be a Proc or method name as symbol.
23
+ # :formats
24
+ # array of formats as symbols.
25
+ # defaults to [:html]
26
+ def response_for(*actions, &block)
27
+ options = actions.extract_options!
28
+ options[:is] ||= block
29
+ formats = options[:formats] || [:html]
30
+
31
+ case options[:on]
32
+ when NilClass, :any
33
+ build_custom_response(actions, :success, formats, options[:is])
34
+ build_custom_response(actions, :failure, formats, options[:is])
35
+ when :success
36
+ build_custom_response(actions, :success, formats, options[:is])
37
+ when :failure
38
+ build_custom_response(actions, :failure, formats, options[:is])
39
+ end
40
+ end
41
+
42
+ def build_custom_response(action_names, success_status, formats, response) #:nodoc:
43
+ action_names.each do |action_name|
44
+ formats.each do |format|
45
+ self.const_get(:Responses)["#{action_name}.#{success_status}.#{format}"] = response
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ module InstaneMethods
52
+ private
53
+ def custom_response_for(action_name, action_status, format)
54
+ if responder = self.class::Responses["#{action_name}.#{action_status}.#{format}"]
55
+ case responder
56
+ when Symbol
57
+ self.send(responder)
58
+ when Proc
59
+ self.instance_eval &responder
60
+ end
61
+ else
62
+ false
63
+ end
64
+ end
65
+
66
+ def default_response_for(action_name, action_status, format)
67
+ if responder = self.class::DefaultResponses["#{action_name}.#{action_status}.#{format}"]
68
+ self.instance_eval &responder
69
+ else
70
+ return false
71
+ end
72
+ end
73
+
74
+ def response_for(action_name, action_status, format = :html)
75
+ format = :html if format == :all
76
+ custom_response_for(action_name, action_status, format) || default_response_for(action_name, action_status, format) || head(:not_acceptable)
77
+ end
78
+ end
79
+ end
80
+ end
@@ -1,26 +1,5 @@
1
1
  module Exposure
2
- module Configuration
3
- # options
4
- # :nested => false or symbol or array of symbols
5
- # defaults to false
6
- # :only => array of REST methods names as symbols to only include
7
- # defaults to [:show, :new, :create, :edit, :update, :destroy]
8
- # :except => array of REST methods to exclude
9
- # defaults to [ ]
10
- # :formats => array of
11
- # defaults to [ :html, :xml, :json ]
12
- def expose_one(resource_name, options = {})
13
- include ActiveSupport::Callbacks
14
- extend Exposure::Common
15
- self.resource_name = resource_name
16
- self.member_nesting = [ [self.resource_name.to_sym] ]
17
-
18
- extend Patterns::Resource
19
- include Patterns::Resource::Actions
20
-
21
- define_callbacks(*Patterns::Resource::Callbacks)
22
- end
23
-
2
+ module Configuration
24
3
  # options
25
4
  # :nested => false or symbol or array of symbols
26
5
  # defaults to false
@@ -29,34 +8,37 @@ module Exposure
29
8
  # :except => array of REST methods to exclude
30
9
  # defaults to [ ]
31
10
  # :formats => array of
32
- # defaults to [ :html, :xml, :json ]
11
+ # defaults to [ :html, :xml]
33
12
  #
34
13
  def expose_many(name, options = {})
35
- include ActiveSupport::Callbacks
36
- extend Exposure::Common
14
+ @_exposed_resource_name = name
15
+ @_exposed_resource_options = options
37
16
 
38
- self.resource_name = name.to_s.singularize
39
- self.resources_name = name.to_s
17
+ extend Configuration::Options
40
18
 
41
- if nesting = options[:nested]
42
-
43
- self.parent_model = nesting.shift.to_s.singularize.camelize.constantize
44
-
45
- build_default_finders(self.resources_name, nesting)
46
-
47
- nesting.collect! {|sym| [sym.to_s.singularize.to_sym, sym]}
48
- self.member_nesting = nesting + [ [self.resource_name.to_sym] ]
49
- self.collection_nesting = nesting + [ [self.resources_name.to_sym] ]
50
- else
51
- self.parent_model = self.resource_name.camelize.constantize
52
- build_default_finders(self.resource_name, [])
53
- self.member_nesting = [ [self.resource_name.to_sym] ]
54
- self.collection_nesting = [ [self.resources_name.to_sym] ]
19
+ class << self
20
+ attr_accessor :resource_name, :resources_name,
21
+ :resource_chain, :resources_chain,
22
+ :collection_nesting, :member_nesting,
23
+ :parent_model
55
24
  end
56
25
 
26
+ include ActiveSupport::Callbacks
27
+ include Exposure::Finding
28
+ include Exposure::Flashing
29
+ include Exposure::Responding
30
+ include Exposure::Callbacks
31
+
32
+ self.name!
33
+ self.build_default_finders!
34
+ self.build_default_builders!
35
+
57
36
  extend Patterns::Resources
58
37
  include Patterns::Resources::Actions
59
38
 
39
+ self.allow_actions!
40
+ self.allow_formats!
41
+
60
42
  define_callbacks(*Patterns::Resources::Callbacks)
61
43
  end
62
44
  alias :expose :expose_many
@@ -0,0 +1,55 @@
1
+ module Exposure
2
+ module Configuration
3
+ module Options
4
+
5
+ def allow_actions!
6
+ if @_exposed_resource_options[:only]
7
+ @_exposed_resource_options[:except] = Patterns::Resources::DefaultActions - @_exposed_resource_options[:only]
8
+ end
9
+
10
+ if @_exposed_resource_options[:except]
11
+ @_exposed_resource_options[:except].each do |action|
12
+ undef_method(action)
13
+ end
14
+ end
15
+ end
16
+
17
+ def allow_formats!
18
+ formats = @_exposed_resource_options[:formats] || [:html, :xml]
19
+ end
20
+
21
+ def name!
22
+ self.resource_name = @_exposed_resource_name.to_s.singularize
23
+ self.resources_name = @_exposed_resource_name.to_s
24
+ end
25
+
26
+ def build_default_finders!
27
+ if nesting = @_exposed_resource_options[:nested]
28
+ self.build_nested_default_finders!(nesting)
29
+ return
30
+ end
31
+
32
+ self.parent_model = self.resource_name.camelize.constantize
33
+ build_default_finders(self.resource_name, [])
34
+ self.member_nesting = [ [self.resource_name.to_sym] ]
35
+ self.collection_nesting = [ [self.resources_name.to_sym] ]
36
+ end
37
+
38
+ def build_default_builders!
39
+ true
40
+ end
41
+
42
+ def build_nested_default_finders!(nesting)
43
+
44
+ self.parent_model = nesting.shift.to_s.singularize.camelize.constantize
45
+
46
+ build_default_finders(self.resources_name, nesting)
47
+
48
+ nesting.collect! {|sym| [sym.to_s.singularize.to_sym, sym]}
49
+
50
+ self.member_nesting = nesting + [ [self.resource_name.to_sym] ]
51
+ self.collection_nesting = nesting + [ [self.resources_name.to_sym] ]
52
+ end
53
+ end
54
+ end
55
+ end