modify_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.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in modify_resource.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Colin Young
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,46 @@
1
+ # ModifyResource
2
+
3
+ ## Installation
4
+
5
+ Add this line to your application's Gemfile:
6
+
7
+ gem 'modify_resource'
8
+
9
+ And then execute:
10
+
11
+ $ bundle
12
+
13
+ Or install it yourself as:
14
+
15
+ $ gem install modify_resource
16
+
17
+ ## Usage
18
+
19
+ #### Including
20
+
21
+ Just include `ModifyResource` in your controller, or, if you want it available in your entire application:
22
+
23
+ ```ruby
24
+ # application.rb
25
+ class ApplicationController < ActionController::Base
26
+
27
+ class << self
28
+ include Rails.application.routes.url_helpers
29
+ end
30
+
31
+ end
32
+ ```
33
+
34
+ #### `redirect_to`
35
+
36
+ You can change how your successful `create`s or `update`s are handled by changing where they redirect to in the `options` hash.
37
+
38
+ Note: If you want to use the `:redirect_to` option, and you want to use Rails routes, you'll need to `include ActionController::Base` in your controller (or ApplicationController) that you also `include ModifyResource` in.
39
+
40
+ ## Contributing
41
+
42
+ 1. Fork it
43
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
44
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
45
+ 4. Push to the branch (`git push origin my-new-feature`)
46
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << "test"
6
+ t.test_files = FileList['test/test*.rb']
7
+ t.verbose = true
8
+ end
9
+
10
+ desc "Run tests"
11
+ task :default => :test
@@ -0,0 +1,236 @@
1
+ require_relative 'resource_info'
2
+ require_relative 'router'
3
+
4
+ module ActionController
5
+
6
+ module ModifyResource
7
+ include ResourceInfo
8
+ include ActionView::Helpers::TextHelper
9
+
10
+ module ClassMethods
11
+
12
+ # A shortcut - just add modify_on :create, :update
13
+ # if your variable is the controller's name -- e.g. @widget in WidgetsController
14
+ def modify_on(*actions)
15
+ # Define in the method so that the user could override if they wanted
16
+ options = actions.extract_options!
17
+ actions.each do |action|
18
+ unless method_defined?(action)
19
+ define_method action do
20
+ modify_resource_with action, options
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ # :nodoc:
28
+ def self.included(base)
29
+ base.extend(ClassMethods)
30
+ end
31
+
32
+ # Handles the usual @var = Model.find(params[:id]); @var.save
33
+ # etc. stuff.
34
+ def modify_resource_with(*args) # ([res=nil, ], verb=:update, options={}, args=nil)
35
+ # Set var to resource matching controller's name if res is a symbol
36
+ if args.first.is_a? Symbol or args.first.is_a? String
37
+ res = instance_variable_get(:"@#{resource_name}")
38
+ else
39
+ res = args.shift
40
+ end
41
+
42
+ # Set up default values
43
+ verb = args[0] || :update
44
+ options = args[1] || {}
45
+ _params = args[2] || nil
46
+ as_user = nil
47
+
48
+ # model_name is this res's model_name
49
+ model_name = res.class.model_name.underscore.downcase
50
+
51
+ # Grab params if not set
52
+ _params ||= params[model_name]
53
+
54
+ # We may need the current user instance
55
+ options[:as_current] ||= options[:as_user] # Backwards compat
56
+
57
+ if options[:as_current] and res.respond_to?(:as_user)
58
+ res.as_user = self.send "current_#{options[:as_current]}"
59
+ end
60
+
61
+ # Actually perform update, or create, destroy, etc.
62
+ modified = case verb
63
+ when :update
64
+ res.update_permitted_attributes(_params)
65
+ when :create
66
+ res.deep_attributes = _params
67
+ res.persisted?
68
+ else
69
+ res.method(verb).arity == 0 ? res.send(verb) : res.send(verb, _params)
70
+ end
71
+
72
+ # the resource was updated
73
+ instance_variable_set :"@#{resource_name}", res
74
+
75
+ raise 'As_user MUST be unset on ALL items.' if res.valid? and res.as_user.present?
76
+
77
+ # We're updating a nested resource, so we need to set its parent for it
78
+ update_resource_parent(res) unless parent_for(res).present?
79
+
80
+ # Actually save or create.
81
+ if modified
82
+
83
+ unless request.xhr?
84
+
85
+ options[:redirect_with_resources] ||= [ :self ]
86
+ after = params[:after]
87
+ unless (path = options[:redirect_to]).blank?
88
+ router = Router.new
89
+ success_path = if options[:redirect_with_resources].blank?
90
+ router.send path
91
+ else
92
+ router.send path, *collect_resources_for(res, options[:redirect_with_resources])
93
+ end
94
+ end
95
+ success_path ||= resource_path_with_base(:production, res)
96
+
97
+ msg = options[:success].try(:call, res)
98
+
99
+ if msg.blank?
100
+
101
+ msg = "#{action_name.capitalize.gsub(/e$/,'')}ed "
102
+
103
+ if after.present? and after.pluralize == after
104
+ # Redirect to the plural (index) page
105
+ model_name = params[:after]
106
+ msg << model_name.pluralize
107
+ success_path << '/' + after
108
+ else
109
+ # Redirect to the show page for the resource.
110
+ # Flash is like 'Widget 2 has been updated'.
111
+ name = String.new.tap do |s|
112
+ break s = res.title if res.respond_to? :title
113
+ break s = res.name if res.respond_to? :name
114
+ s = res.id
115
+ end
116
+ msg << "#{model_name.humanize.downcase} '#{truncate(name, length: 20)}'"
117
+ end
118
+ end
119
+
120
+ flash[:notice] = msg
121
+ redirect_to success_path
122
+ else
123
+ render json: res
124
+ end
125
+ else
126
+ messages = res.errors.messages
127
+ unless request.xhr?
128
+ flash[:error] = messages
129
+ begin
130
+ render :edit
131
+ rescue
132
+ # They didn't respond to that action
133
+ if res.persisted?
134
+ render :show
135
+ else
136
+ render :new
137
+ end
138
+ end
139
+ else
140
+ render json: {errors: messages}, status: :unprocessable_entity
141
+ end
142
+ end
143
+ end
144
+
145
+ private
146
+
147
+ # :nodoc:
148
+ def resource_path_with_base(base, res)
149
+ components, resources = path_components_for(res, base).try(:compact)
150
+
151
+ return url_for unless components.present?
152
+
153
+ unless components.nil? || components.empty?
154
+ path = components.join('_') + '_path'
155
+ send(path, *resources)
156
+ else
157
+ :"#{base.to_s.pluralize}"
158
+ end
159
+ end
160
+
161
+ # :nodoc: Climbs up the resource's parent associations to generate a rails route
162
+ def path_components_for(res, base, components=[], resources=[])
163
+ return nil unless res.present?
164
+
165
+ component = component_for(res)
166
+
167
+ # Redirect to the index if the res was just deleted
168
+ component = component.pluralize unless res.persisted?
169
+
170
+ components.unshift component
171
+ resources.unshift res if res.persisted?
172
+
173
+ unless component.to_s == base.to_s
174
+ path_components_for(parent_for(res), base, components, resources)
175
+ else
176
+ [components, resources]
177
+ end
178
+ end
179
+
180
+ # :nodoc: gets path component for a resource
181
+ def component_for(res)
182
+ res.class.model_name.downcase
183
+ end
184
+
185
+ # :nodoc: gets a nested resource's parent
186
+ def parent_for(res)
187
+ parents = possible_parents_for(res)
188
+ return nil unless parents.count == 1
189
+
190
+ component = component_for(res)
191
+ parent_component = parents[0].sub('_id', '')
192
+ res.send(parent_component)
193
+ end
194
+
195
+ # :nodoc: gets possible parents based on attributes ending in '_id'
196
+ def possible_parents_for(res)
197
+ Array.new.tap do |possibilities|
198
+ res.attributes.keys.each do |field|
199
+ next unless field[/_id$/]
200
+ cleaned = field.sub '_id', ''
201
+ # Fields that end in _id but do not point to a constant are ignored.
202
+ possibilities << cleaned if Object.const_defined? cleaned.classify
203
+ end
204
+ end
205
+ end
206
+
207
+ # :nodoc: Adds the resource to its parent
208
+ def update_resource_parent(res)
209
+ parents = possible_parents_for(res)
210
+ return if parents.empty? or parents.count > 1
211
+
212
+ if parents.count > 1
213
+ raise "Can't guess parent, multiple options for resource.\n#{res.inspect}\n#{parents.inspect}"
214
+ end
215
+
216
+ parent_class = parents.first.classify.constantize
217
+ parent_name = parent_class.model_name.downcase
218
+ parent_param = parent_name + '_id'
219
+ parent = parent_class.find(params[parent_param])
220
+ return unless parent.present?
221
+
222
+ instance_variable_set :"@#{parent_name}", parent
223
+
224
+ child_name = res.class.model_name.downcase.pluralize
225
+ child_name = child_name.singularize if !parent.respond_to?(child_name)
226
+
227
+ association = parent.send(child_name)
228
+ association << res
229
+ end
230
+
231
+ # Converts a list of symbols into the items necessary to compose redirection URLS
232
+ def collect_resources_for res, arr
233
+ arr.collect { |i| res.send(i) }
234
+ end
235
+ end
236
+ end
@@ -0,0 +1,22 @@
1
+ module ActionController
2
+ module ModifyResource
3
+ module ResourceInfo
4
+
5
+ def resource_name
6
+ controller_name[/(\w+)$/].singularize
7
+ end
8
+
9
+ def model_class
10
+ resource_name.capitalize.constantize
11
+ end
12
+
13
+ def resource
14
+ res = instance_variable_get "@#{resource_name}"
15
+ begin
16
+ res ||= model_class.find params[:id]
17
+ rescue; end
18
+ res
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ module ActionController
2
+ module ModifyResource
3
+ class Router
4
+
5
+ def initialize
6
+ self.class.send :include, Rails.application.routes.url_helpers
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,87 @@
1
+ module ActionController
2
+
3
+ module UpdateAs
4
+
5
+ module ClassMethods
6
+
7
+ def update_as_current(user_class=:user, nested_resources={})
8
+ append_before_filter do
9
+ return unless [:PUT, :POST, :PATCH].include?(request.method.to_sym) and
10
+ params[:_method] != "delete"
11
+
12
+ update_as(self.send(:"current_#{user_class}"), resource, nested_resources)
13
+ end
14
+ end
15
+
16
+ def update_as_current_user(nested_resources={})
17
+ update_as_current :user, nested_resources
18
+ end
19
+
20
+ end
21
+
22
+ def update_as(user, current_resource, nested_resources={})
23
+ case nested_resources
24
+ when Symbol, String, Array
25
+ update_resource(current_resource, Array(nested_resources), as: user)
26
+ else
27
+ return update_resource(current_resource, as: user) if nested_resources.empty?
28
+
29
+ nested_resources.each do |res, fields|
30
+ res = if res.to_s == current_resource.class.name.downcase
31
+ current_resource
32
+ else
33
+ current_resource.send(res)
34
+ end
35
+ update_resource res, fields, as: user
36
+ end
37
+ end
38
+ end
39
+
40
+ def self.included(base)
41
+ base.extend(ClassMethods)
42
+ end
43
+
44
+ private
45
+
46
+ def add_user_id_to(hash_or_user, user_hash)
47
+ return unless hash_or_user.present?
48
+ raise UserNotProvidedError unless user = user_hash[:as]
49
+ user_class = user.class.model_name.downcase.underscore # 'user', etc.
50
+
51
+ case hash_or_user
52
+ when Hash
53
+ hash_or_user[:"#{user_class}_identifier"] = user.id
54
+ else
55
+ hash_or_user.send :"#{user_class}=", user
56
+ end
57
+ end
58
+
59
+ def update_resource(*args) # resource, (optional: fields=[]), user_hash={}
60
+ resource = args.first
61
+ user_hash = args.last
62
+ raise UserNotProvidedError unless user = user_hash[:as]
63
+ fields = args[1] if args.count > 2
64
+
65
+ resource_name = resource.class.name.downcase
66
+ parameters = params[resource_name]
67
+
68
+ if parameters.present? and fields.present?
69
+ fields.each do |field|
70
+
71
+ field_attribute = field.to_s + '_attributes' unless field[/_attributes/].present?
72
+ handle = parameters[field_attribute]
73
+
74
+ handle = [handle] unless handle.is_a?(Array)
75
+ handle.each do |individual_resource|
76
+ add_user_id_to(individual_resource, as: user)
77
+ end
78
+ end
79
+ else
80
+ add_user_id_to(resource, as: user)
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ class UserNotProvidedError < StandardError
87
+ end
@@ -0,0 +1,90 @@
1
+ module ActiveModel
2
+
3
+ # This variable is to aid models methods that need the current user.
4
+ # It is very different from solutions that use Thread --
5
+ # 1. First of all, it's paired with modify_resource_with, and
6
+ # 2. I've hooked into after_save to double-ensure that the
7
+ # @as_user variable is unset after any change.
8
+
9
+ module UpdatePermittedAttributes
10
+ def update_permitted_attributes(attributes)
11
+ if attributes.all_permitted?
12
+ update_attributes(attributes, without_protection: true)
13
+ else
14
+ update_attributes(attributes)
15
+ end
16
+ end
17
+
18
+ def deep_attributes=(attributes)
19
+ attributes.each do |key, value|
20
+ next unless key.to_s[m = /_attributes$/]
21
+ nested = self.send key.gsub(m, '')
22
+ if nested.respond_to? :each
23
+ self.send(nested).each do |built|
24
+ value.map { |sub_params| built.attributes = sub_params }
25
+ end
26
+ attributes.delete(key)
27
+ else
28
+ nested.attributes = value
29
+ end
30
+ end
31
+ self.attributes = attributes
32
+ save
33
+ end
34
+
35
+ # Hook into models that accept nested attributes.
36
+ module ClassMethods
37
+
38
+ def accepts_nested_attributes_for(field, options={})
39
+
40
+ before_validation do
41
+ return unless @as_user.present?
42
+ child = self.send(field)
43
+
44
+ # Copy down the chain as needed.
45
+ # As_user will be unset on both models after save.
46
+ if child.respond_to? :map
47
+ children = child
48
+ children.map {|c| c.as_user = @as_user }
49
+ else
50
+ child.try(:as_user=, @as_user)
51
+ end
52
+ end
53
+
54
+ super(field, options)
55
+ end
56
+
57
+ end
58
+
59
+ # Add/override statechanging methods to ensure @as_user is unset
60
+ def self.included(base)
61
+ # We need ActiveModel callbacks
62
+ base.extend ActiveModel::Callbacks
63
+
64
+ # Add our stuff
65
+ base.send :attr_accessor, :as_user
66
+ base.extend ClassMethods
67
+
68
+ [:after_save, :after_destroy].each do |m|
69
+ base.send(m) do
70
+ self.as_user = nil
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ end
77
+
78
+ ActiveRecord::Base.send :include, ActiveModel::UpdatePermittedAttributes
79
+
80
+ class Hash
81
+
82
+ def all_permitted?
83
+ self.each do |key, value|
84
+ if value.is_a?(Hash)
85
+ return true unless value.respond_to? :all_permitted? # For those without security enabled.
86
+ return false if !value.all_permitted? and !key.numeric?
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,50 @@
1
+ module MixedIdentifierForUserResource
2
+ def has_mixed_identifier_for(user_resource, options={})
3
+
4
+ user_resource = user_resource.to_s
5
+
6
+ self.send :attr_accessible, :"#{user_resource}_identifier"
7
+
8
+ instance_eval <<-END
9
+ validate :"#{user_resource}_identifier", presence: true
10
+ END
11
+
12
+ class_eval <<-END
13
+ def #{user_resource}_identifier=(identifier)
14
+ if identifier.is_a? Fixnum or identifier.numeric? or identifier.parameter_id?
15
+ self.#{user_resource}_id = identifier
16
+ else
17
+ # Try to uncover the as_user of either this resource or the parent
18
+ self.#{user_resource} = #{user_resource.classify}.find_or_initialize_by_email(identifier)
19
+ end
20
+ end
21
+
22
+ def #{user_resource}_identifier
23
+ resource = self.#{user_resource}
24
+ resource.try(:id) || resource.try(:email) || resource.try(:email_address)
25
+ end
26
+
27
+ def mass_assignment_authorizer(role)
28
+ super(role) << "#{user_resource}_identifier"
29
+ end
30
+
31
+ before_validation do
32
+ if #{user_resource}.present? and #{user_resource}.new_record? and #{user_resource}.respond_to? :invite!
33
+ #{user_resource}.invite! @as_user
34
+ self.#{user_resource}_id = #{user_resource}.id
35
+ end
36
+ end
37
+ END
38
+
39
+ end
40
+ end
41
+
42
+ class String
43
+
44
+ # Is the string something like '234234234-Joe-Test'? This is used in params.
45
+ def parameter_id?
46
+ self[/^[0-9]+\-[\D]+/].present?
47
+ end
48
+ end
49
+
50
+ ActiveRecord::Base.extend(MixedIdentifierForUserResource)
@@ -0,0 +1,3 @@
1
+ module ModifyResource
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,22 @@
1
+ require "require_all"
2
+
3
+ $: << File.dirname(__FILE__)
4
+
5
+ require "modify_resource/version"
6
+ require "modify_resource/rails/action_controller/modify_resource"
7
+ require "modify_resource/rails/action_controller/update_as"
8
+ require "modify_resource/rails/active_model/update_permitted_attributes"
9
+ require "modify_resource/rails/active_record/mixed_identifier_for_user_resource"
10
+
11
+ module ModifyResource
12
+
13
+ def self.included(base)
14
+ if defined? Rails and base < ActionController::Base
15
+
16
+ # Add `modify_on` and other methods to the controller
17
+ base.send :include, ActionController::ModifyResource
18
+ base.send :include, ActionController::UpdateAs
19
+ end
20
+ end
21
+
22
+ end
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'modify_resource/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "modify_resource"
8
+ gem.version = ModifyResource::VERSION
9
+ gem.authors = ["Colin Young"]
10
+ gem.email = ["me@colinyoung.com"]
11
+ gem.description = %q{This gem makes rails automatic. Securely.}
12
+ gem.summary = %q{stop writing the same controller actions for resources}
13
+ gem.homepage = ""
14
+ gem.add_dependency "require_all"
15
+ gem.add_dependency "rake"
16
+
17
+ gem.files = `git ls-files`.split($/)
18
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
19
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
20
+ gem.require_paths = ["lib"]
21
+ end
@@ -0,0 +1 @@
1
+ require 'test_helper'
File without changes
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: modify_resource
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Colin Young
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: require_all
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: This gem makes rails automatic. Securely.
47
+ email:
48
+ - me@colinyoung.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .gitignore
54
+ - Gemfile
55
+ - LICENSE.txt
56
+ - README.md
57
+ - Rakefile
58
+ - lib/modify_resource.rb
59
+ - lib/modify_resource/rails/action_controller/modify_resource.rb
60
+ - lib/modify_resource/rails/action_controller/resource_info.rb
61
+ - lib/modify_resource/rails/action_controller/router.rb
62
+ - lib/modify_resource/rails/action_controller/update_as.rb
63
+ - lib/modify_resource/rails/active_model/update_permitted_attributes.rb
64
+ - lib/modify_resource/rails/active_record/mixed_identifier_for_user_resource.rb
65
+ - lib/modify_resource/version.rb
66
+ - modify_resource.gemspec
67
+ - test/modify_resource_test.rb
68
+ - test/test_helper.rb
69
+ homepage: ''
70
+ licenses: []
71
+ post_install_message:
72
+ rdoc_options: []
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ requirements: []
88
+ rubyforge_project:
89
+ rubygems_version: 1.8.24
90
+ signing_key:
91
+ specification_version: 3
92
+ summary: stop writing the same controller actions for resources
93
+ test_files:
94
+ - test/modify_resource_test.rb
95
+ - test/test_helper.rb