exposure 0.0.6 → 0.0.7

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/.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