singular_resource 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3f053e2406cc78d4fe7039e2aa1d1aa66b52d120
4
+ data.tar.gz: a4ce51239058b9c8b948a2a033ee337f5b2481b5
5
+ SHA512:
6
+ metadata.gz: c4eac4db87ae958755b2f441de10a40a5d5016d8b6cd160c4504729bf9fcfd13089967fd86605d9683c698f10edc589adf08bc6015729654206d3d73c4580b94
7
+ data.tar.gz: 49b1a5f63fffbfab073923ad6a39b2eab8e0fc441c4cfdd4d1dcf621ddca7d2758d104aa7d11921453729322d6175286026914308143c86419e86b1cc667b14c
data/README.md ADDED
@@ -0,0 +1,164 @@
1
+ Singular Resource
2
+ =====================
3
+
4
+ Extracted from decent exposure, attempts to leave the useful parts, and just use `helper_method` to expose your view models.
5
+
6
+ ## DOES
7
+ Allow you to find or initialize a simple resource, removing the boilerplate from CRUD actions.
8
+
9
+
10
+ ## DOES NOT
11
+ Expose the model in any way, scope the query to a collection method if defined, or deal with collections.
12
+
13
+
14
+ ## Use
15
+ It provides a private method that performs a query for the document when invoked, unless the id is not defined (`new`, `create`), in which case it returns an initialized model.
16
+ ```ruby
17
+ singular_resource :patient
18
+ ```
19
+
20
+ #### Strategies
21
+ Like `decent_exposure`, it's configurable, and provides different strategies.
22
+ By default, it uses `StrongParametersStrategy`, which only assigns the attributes if a method name is provided via the `attributes` option.
23
+
24
+ #### Options
25
+ ``` ruby
26
+ :optional => "True if shouldn't fail if document does not exist",
27
+
28
+ :model => "Class or name of the model class",
29
+
30
+ :finder_parameter => "Name of the parameter that has the document's id",
31
+
32
+ :attributes => "Name of the attributes method name if using strong parameters",
33
+
34
+ :param_key => "Name of the parameter that has the document's attributes"
35
+ ```
36
+
37
+ ## Comparison
38
+ What `singular_resource` proposes is that you go from this:
39
+
40
+ ```ruby
41
+ class Controller
42
+ def new
43
+ @person = Person.new(params[:person])
44
+ end
45
+
46
+ def create
47
+ @person = Person.new(params[:person])
48
+ if @person.save
49
+ redirect_to(@person)
50
+ else
51
+ render :new
52
+ end
53
+ end
54
+
55
+ def edit
56
+ @person = Person.find(params[:id])
57
+ end
58
+
59
+ def update
60
+ @person = Person.find(params[:id])
61
+ if @person.update_attributes(params[:person])
62
+ redirect_to(@person)
63
+ else
64
+ render :edit
65
+ end
66
+ end
67
+ end
68
+ ```
69
+
70
+ To something like this:
71
+
72
+ ```ruby
73
+ class Controller
74
+ expose(:person)
75
+
76
+ def create
77
+ if person.save
78
+ redirect_to(person)
79
+ else
80
+ render :new
81
+ end
82
+ end
83
+
84
+ def update
85
+ if person.save
86
+ redirect_to(person)
87
+ else
88
+ render :edit
89
+ end
90
+ end
91
+ end
92
+ ```
93
+
94
+ ### With [draper](http://github.com/drapergem/draper)
95
+
96
+ If you use decorators, you can go from something like this:
97
+
98
+ ```ruby
99
+ class Controller
100
+ def new
101
+ @person = Person.new(params[:person]).decorate
102
+ end
103
+
104
+ def create
105
+ @person = Person.new(params[:person])
106
+ if @person.save
107
+ redirect_to(@person)
108
+ else
109
+ @person = @person.decorate
110
+ render :new
111
+ end
112
+ end
113
+
114
+ def edit
115
+ @person = Person.find(params[:id]).decorate
116
+ end
117
+
118
+ def update
119
+ @person = Person.find(params[:id])
120
+ if @person.update_attributes(params[:person])
121
+ redirect_to(@person)
122
+ else
123
+ @person = @person.decorate
124
+ render :edit
125
+ end
126
+ end
127
+ end
128
+ ```
129
+
130
+ To something like this:
131
+
132
+ ```ruby
133
+ class Controller
134
+ before_filter :decorate_person
135
+
136
+ singular_resource(:person)
137
+
138
+ def create
139
+ if person.save
140
+ redirect_to(person)
141
+ else
142
+ render :new
143
+ end
144
+ end
145
+
146
+ def update
147
+ if person.save
148
+ redirect_to(person)
149
+ else
150
+ render :edit
151
+ end
152
+ end
153
+
154
+ private
155
+ def decorate_person
156
+ @person = person.decorate
157
+ end
158
+ end
159
+ ```
160
+
161
+ If you think that the `before_filter` is nasty or don't like ivars in your views, so do I! Check the [present](http://github.com/ElMassimo/present) gem
162
+
163
+ ### Special Thanks
164
+ Singular Resource is a subset of [decent_exposure](https://github.com/voxdolo/decent_exposure).
@@ -0,0 +1,19 @@
1
+ module SingularResource
2
+ class Configuration
3
+ def initialize(&block)
4
+ instance_exec(&block) if block_given?
5
+ end
6
+
7
+ def merge(other)
8
+ options.merge(other)
9
+ end
10
+
11
+ def options
12
+ @options ||= {}
13
+ end
14
+
15
+ def method_missing(key,value)
16
+ self.options[key] = value
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,4 @@
1
+ module SingularResource
2
+ # Public: A generic Error class for singular_resource
3
+ class Error < ::StandardError; end
4
+ end
@@ -0,0 +1,17 @@
1
+ require 'singular_resource/inflector'
2
+
3
+ module SingularResource
4
+ class Finder
5
+ attr_accessor :name, :strategy, :options
6
+
7
+ def initialize(name, strategy, options)
8
+ self.name = name.to_s
9
+ self.strategy = strategy
10
+ self.options = options
11
+ end
12
+
13
+ def call(controller)
14
+ strategy.new(controller, name, options).resource
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ require 'singular_resource/finder'
2
+ require 'singular_resource/strategies/strong_parameters_strategy'
3
+
4
+ module SingularResource
5
+ class FinderStrategizer
6
+
7
+ def self.strategy_for(name, options={})
8
+ strategy_class = options.delete(:strategy) || Strategies::StrongParametersStrategy
9
+ options = options.merge(name: name)
10
+ Finder.new(name, strategy_class, options)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,27 @@
1
+ require 'active_support/inflector'
2
+ require 'active_support/core_ext/string'
3
+
4
+ module SingularResource
5
+ class Inflector
6
+ attr_reader :original, :model
7
+
8
+ def initialize(name, model)
9
+ @original = name.to_s
10
+ @model = model
11
+ end
12
+
13
+ alias name original
14
+
15
+ def param_key
16
+ model.name.param_key
17
+ end
18
+
19
+ def parameter
20
+ "#{model.name.singularize}_id"
21
+ end
22
+
23
+ def self.class_for(name)
24
+ name.to_s.classify.constantize
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,55 @@
1
+ require 'singular_resource/finder_strategizer'
2
+ require 'singular_resource/configuration'
3
+ require 'simple_memoizer'
4
+
5
+ module SingularResource
6
+ module Resource
7
+ extend ActiveSupport::Concern
8
+ include SimpleMemoizer
9
+
10
+ included do
11
+ class_attribute :_singular_configurations
12
+ self._singular_configurations ||= Hash.new(Configuration.new)
13
+ end
14
+
15
+ module ClassMethods
16
+ def singular_configuration(name=:default,&block)
17
+ self._singular_configurations = _singular_configurations.merge(name => Configuration.new(&block))
18
+ end
19
+
20
+ def singular_resource(name, options={})
21
+ enforce_method_name_not_used!(name)
22
+
23
+ config = options[:config] || :default
24
+ options = _singular_configurations[config].merge(options)
25
+
26
+ _resource_finders[name] = finder = FinderStrategizer.strategy_for(name, options)
27
+
28
+ define_resource_method(name, finder)
29
+ end
30
+
31
+ private
32
+
33
+ def _resource_finders
34
+ @_resource_finders ||= {}
35
+ end
36
+
37
+ def define_resource_method(name, finder)
38
+ define_method(name) do
39
+ finder.call(self)
40
+ end
41
+ memoize name
42
+ hide_action name
43
+ end
44
+
45
+ def enforce_method_name_not_used!(name)
46
+ if ActionController::Base.instance_methods.include?(name.to_sym)
47
+ Kernel.abort "[ERROR] You are adding a singular resource by the `#{name}` method, " \
48
+ "which overrides an existing ActionController method of the same name. " \
49
+ "Consider a different resource name\n" \
50
+ "#{caller.first}"
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,20 @@
1
+ module SingularResource
2
+ module Strategies
3
+ module AssignAttributes
4
+
5
+ def attributes
6
+ raise 'Implement in submodule'
7
+ end
8
+
9
+ def assign_attributes?
10
+ !get? && !delete? && attributes.present?
11
+ end
12
+
13
+ def resource
14
+ super.tap do |r|
15
+ r.attributes = attributes if r && assign_attributes?
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ require 'singular_resource/strategies/assign_attributes'
2
+
3
+ module SingularResource
4
+ module Strategies
5
+ module AssignFromMethod
6
+ include AssignAttributes
7
+
8
+ def attributes
9
+ @attributes ||= method_attributes || {}
10
+ end
11
+
12
+ private
13
+
14
+ def method_attributes
15
+ controller.send(options[:attributes]) if options[:attributes]
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ require 'singular_resource/strategies/assign_attributes'
2
+
3
+ module SingularResource
4
+ module Strategies
5
+ module AssignFromParams
6
+ include AssignAttributes
7
+
8
+ def attributes
9
+ @attributes ||= params[param_key] || {}
10
+ end
11
+
12
+ private
13
+
14
+ def param_key
15
+ options[:param_key] || inflector.param_key
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,8 @@
1
+ require 'singular_resource/strategies/mongoid_strategy'
2
+ require 'singular_resource/strategies/assign_from_params'
3
+
4
+ module SingularResource
5
+ class EagerAttributesStrategy < MongoidStrategy
6
+ include Strategies::AssignFromParams
7
+ end
8
+ end
@@ -0,0 +1,25 @@
1
+ require 'singular_resource/strategy'
2
+ require 'active_support/core_ext/module/delegation'
3
+
4
+ module SingularResource
5
+ class MongoidStrategy < Strategy
6
+ delegate :get?, :delete?, :to => :request
7
+ delegate :parameter, :to => :inflector
8
+
9
+ def id
10
+ params[parameter] || params[finder_parameter]
11
+ end
12
+
13
+ def finder_parameter
14
+ options[:finder_parameter] || :id
15
+ end
16
+
17
+ def resource
18
+ if id
19
+ options[:optional] ? model.where(id: id).first : model.find(id)
20
+ else
21
+ model.new
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,10 @@
1
+ require 'singular_resource/strategies/mongoid_strategy'
2
+ require 'singular_resource/strategies/assign_from_method'
3
+
4
+ module SingularResource
5
+ module Strategies
6
+ class StrongParametersStrategy < MongoidStrategy
7
+ include Strategies::AssignFromMethod
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,40 @@
1
+ require 'singular_resource/inflector'
2
+
3
+ module SingularResource
4
+ class Strategy
5
+ attr_reader :controller, :name, :options
6
+ attr_writer :model, :inflector
7
+
8
+ def initialize(controller, name, options={})
9
+ @controller, @name, @options = controller, name.to_s, options
10
+ end
11
+
12
+ def resource
13
+ raise 'Implement in subclass'
14
+ end
15
+
16
+ protected
17
+
18
+ def inflector
19
+ @inflector ||= SingularResource::Inflector.new(name, model)
20
+ end
21
+
22
+ def model
23
+ @model ||= case options[:model]
24
+ when Class, Module
25
+ options[:model]
26
+ else
27
+ name_or_model = options[:model] || name
28
+ SingularResource::Inflector.class_for(name_or_model)
29
+ end
30
+ end
31
+
32
+ def params
33
+ controller.params
34
+ end
35
+
36
+ def request
37
+ controller.request
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,6 @@
1
+ require 'singular_resource/resource'
2
+ require 'singular_resource/error'
3
+
4
+ ActiveSupport.on_load(:action_controller) do
5
+ include SingularResource::Resource
6
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: singular_resource
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Máximo Mussini
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: simple_memoizer
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Extracted from decent exposure, attempts to leave the useful parts, and
42
+ just use `helper_method` to expose your view models.
43
+ email:
44
+ - maximomussini@gmail.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files:
48
+ - README.md
49
+ files:
50
+ - README.md
51
+ - lib/singular_resource.rb
52
+ - lib/singular_resource/configuration.rb
53
+ - lib/singular_resource/error.rb
54
+ - lib/singular_resource/finder.rb
55
+ - lib/singular_resource/finder_strategizer.rb
56
+ - lib/singular_resource/inflector.rb
57
+ - lib/singular_resource/resource.rb
58
+ - lib/singular_resource/strategies/assign_attributes.rb
59
+ - lib/singular_resource/strategies/assign_from_method.rb
60
+ - lib/singular_resource/strategies/assign_from_params.rb
61
+ - lib/singular_resource/strategies/eager_attributes_strategy.rb
62
+ - lib/singular_resource/strategies/mongoid_strategy.rb
63
+ - lib/singular_resource/strategies/strong_parameters_strategy.rb
64
+ - lib/singular_resource/strategy.rb
65
+ homepage: https://github.com/ElMassimo/singular_resource
66
+ licenses:
67
+ - MIT
68
+ metadata: {}
69
+ post_install_message:
70
+ rdoc_options:
71
+ - --charset=UTF-8
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '2.0'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubyforge_project:
86
+ rubygems_version: 2.2.2
87
+ signing_key:
88
+ specification_version: 4
89
+ summary: Subset of decent_exposure, leaves the good parts and dismisses the 'magic'
90
+ test_files: []