singular_resource 0.0.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.
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: []