has_crud_for 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,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in has_crud_for.gemspec
4
+ gemspec
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2011 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,70 @@
1
+ = HasCrudFor
2
+
3
+ Follow Law of Demeter in ActiveRecord models.
4
+
5
+ HasCrudFor is a small meta-programming snippet that adds find_*, build_*, create_*, update_* and destroy_* methods intended as a better API for your associations.
6
+
7
+ == Example
8
+
9
+ class Blog < ActiveRecord::Base
10
+ has_many :posts
11
+
12
+ extend HasCrudFor
13
+ has_crud_for :posts
14
+ has_crud_for :comments, :through => :posts
15
+ end
16
+
17
+ class Post
18
+ has_many :comments
19
+ end
20
+
21
+ blog.create_post(post_attributes)
22
+ blog.build_post(post_attributes)
23
+ blog.create_comment(post_id, comment_attributes)
24
+ blog.create_comment!(post_id, comment_attributes) # will raise exception upon failed validation
25
+
26
+ == Benefits
27
+
28
+ * easily delegate methods to other objects:
29
+
30
+ class User
31
+ belongs_to :blog
32
+ delegate :create_post, :to => :blog
33
+ end
34
+
35
+ * replace methods with own implementation
36
+
37
+ class Blog
38
+ has_crud_for :posts
39
+
40
+ def create_post(attributes)
41
+ posts.create(attributes).tap { |post| post.publish! }
42
+ end
43
+ end
44
+
45
+ You can do whatever you need when creating new post, without hunting for blog.posts.create through your codebase! And without resorting to ActiveRecord callbacks.
46
+
47
+ * less coupling - objects don't have to know about internal structure of other objects
48
+
49
+ * easier to mock in tests
50
+
51
+ == Options
52
+
53
+ * :only, :except - specify which methods should be generated; please note that :create generates two methods: create_* and create_*!
54
+ has_crud_for :posts, :only => [:find, :create]
55
+ has_crud_for :posts, :except => [:destroy]
56
+ * :as - use different prefix in method names
57
+ has_crud_for :posts, :as => :entries # generates methods create_entry, build_entry, etc.
58
+ * :through - create methods for nested associations
59
+ has_crud_for :comments, :through => :posts
60
+ has_crud_for :comments, :through => :posts, :as => :posts_comments
61
+
62
+ == FAQ
63
+
64
+ * Do I need to use ActiveRecord? Or Rails?
65
+
66
+ No. But HasCrudFor depends on inflections from ActiveSupport. And that pulls i18n gem as well.
67
+
68
+ == License
69
+
70
+ This project rocks and uses MIT-LICENSE.
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ task :default => :spec
5
+
6
+ desc "Run specs"
7
+ RSpec::Core::RakeTask.new("spec") do |t|
8
+ t.pattern = "spec/{*_spec.rb}"
9
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "has_crud_for/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "has_crud_for"
7
+ s.version = HasCrudFor::VERSION
8
+ s.authors = ["Jan Dudek"]
9
+ s.email = ["jd@jandudek.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{Law of Demeter in ActiveRecord models}
12
+ s.description = %q{HasCrudFor is a small meta-programming snippet that adds find_*, build_*, create_*, update_* and destroy_* methods intended as a better API for your associations}
13
+
14
+ s.rubyforge_project = "has_crud_for"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_development_dependency "rake"
22
+ s.add_development_dependency "rspec"
23
+
24
+ s.add_runtime_dependency "activesupport"
25
+ s.add_runtime_dependency "i18n"
26
+ end
@@ -0,0 +1,3 @@
1
+ module HasCrudFor
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,83 @@
1
+ require "has_crud_for/version"
2
+ require "active_support/core_ext/string/inflections"
3
+ require 'active_support/core_ext/module/introspection'
4
+
5
+ module HasCrudFor
6
+ DEFAULT_METHODS = [:find, :build, :create, :update, :destroy]
7
+
8
+ def has_crud_for(models, options = {})
9
+ methods = begin
10
+ if only = options[:only]
11
+ only
12
+ elsif except = options[:except]
13
+ DEFAULT_METHODS - except
14
+ else
15
+ DEFAULT_METHODS
16
+ end
17
+ end
18
+
19
+ name = (options[:as] || models).to_s.singularize
20
+ if through = options[:through]
21
+ parent = through.to_s.singularize
22
+ define_crud_through_methods(models, name, parent, methods)
23
+ else
24
+ define_crud_methods(models, name, methods)
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def define_crud_methods(models, name, methods = [])
31
+ define_method "find_#{name}".to_sym do |id|
32
+ send(models).find(id)
33
+ end if methods.include?(:find)
34
+
35
+ define_method "build_#{name}".to_sym do |hash = {}|
36
+ send(models).build(hash)
37
+ end if methods.include?(:build)
38
+
39
+ define_method "create_#{name}".to_sym do |hash = {}|
40
+ send(models).create(hash)
41
+ end if methods.include?(:create)
42
+
43
+ define_method "create_#{name}!".to_sym do |hash = {}|
44
+ send(models).create!(hash)
45
+ end if methods.include?(:create)
46
+
47
+ define_method "update_#{name}".to_sym do |id, hash|
48
+ send(models).update(id, hash)
49
+ end if methods.include?(:update)
50
+
51
+ define_method "destroy_#{name}".to_sym do |id|
52
+ send(models).destroy(id)
53
+ end if methods.include?(:destroy)
54
+ end
55
+
56
+ def define_crud_through_methods(models, name, parent, methods = [])
57
+ model_name = models.to_s.singularize
58
+
59
+ define_method "find_#{name}".to_sym do |parent_id, id|
60
+ send("find_#{parent}", parent_id).send("find_#{model_name}", id)
61
+ end if methods.include?(:find)
62
+
63
+ define_method "build_#{name}".to_sym do |parent_id, hash = {}|
64
+ send("find_#{parent}", parent_id).send("build_#{model_name}", hash)
65
+ end if methods.include?(:build)
66
+
67
+ define_method "create_#{name}".to_sym do |parent_id, hash = {}|
68
+ send("find_#{parent}", parent_id).send("create_#{model_name}", hash)
69
+ end if methods.include?(:create)
70
+
71
+ define_method "create_#{name}!".to_sym do |parent_id, hash = {}|
72
+ send("find_#{parent}", parent_id).send("create_#{model_name}!", hash)
73
+ end if methods.include?(:create)
74
+
75
+ define_method "update_#{name}".to_sym do |parent_id, id, hash|
76
+ send("find_#{parent}", parent_id).send("update_#{model_name}", id, hash)
77
+ end if methods.include?(:update)
78
+
79
+ define_method "destroy_#{name}".to_sym do |parent_id, id|
80
+ send("find_#{parent}", parent_id).send("destroy_#{model_name}", id)
81
+ end if methods.include?(:destroy)
82
+ end
83
+ end
@@ -0,0 +1,138 @@
1
+ require File.dirname(__FILE__) + "/../lib/has_crud_for"
2
+
3
+ describe HasCrudFor do
4
+ describe "without :through" do
5
+ before do
6
+ klass = Class.new do
7
+ extend HasCrudFor
8
+ has_crud_for :items
9
+ end
10
+ @subject = klass.new
11
+ @items = mock
12
+ @subject.stub!(:items).and_return(@items)
13
+ @id = 1
14
+ @attributes = {}
15
+ end
16
+
17
+ it "should have find_item" do
18
+ @items.should_receive(:find).with(@id)
19
+ @subject.find_item(@id)
20
+ end
21
+
22
+ it "should have build_item" do
23
+ @items.should_receive(:build).with(@attributes)
24
+ @subject.build_item(@attributes)
25
+ end
26
+
27
+ it "should have create_item" do
28
+ @items.should_receive(:create).with(@attributes)
29
+ @subject.create_item(@attributes)
30
+ end
31
+
32
+ it "should have create_item!" do
33
+ @items.should_receive(:create!).with(@attributes)
34
+ @subject.create_item!(@attributes)
35
+ end
36
+
37
+ it "should have update_item" do
38
+ @items.should_receive(:update).with(@id, @attributes)
39
+ @subject.update_item(@id, @attributes)
40
+ end
41
+
42
+ it "should have destroy_item" do
43
+ @items.should_receive(:destroy).with(@id)
44
+ @subject.destroy_item(@id)
45
+ end
46
+ end
47
+
48
+ describe "with :through" do
49
+ before do
50
+ klass = Class.new do
51
+ extend HasCrudFor
52
+ has_crud_for :children, :through => :parents
53
+ end
54
+ @subject = klass.new
55
+ @parent_id = 1
56
+ @child_id = 2
57
+ @attributes = {}
58
+ @parent = mock
59
+ @children = mock
60
+ @subject.stub!(:find_parent).with(@parent_id).and_return(@parent)
61
+ end
62
+
63
+ it "should have find_child" do
64
+ @parent.should_receive(:find_child).with(@child_id)
65
+ @subject.find_child(@parent_id, @child_id)
66
+ end
67
+
68
+ it "should have build_child" do
69
+ @parent.should_receive(:build_child).with(@attributes)
70
+ @subject.build_child(@parent_id, @attributes)
71
+ end
72
+
73
+ it "should have create_child" do
74
+ @parent.should_receive(:create_child).with(@attributes)
75
+ @subject.create_child(@parent_id, @attributes)
76
+ end
77
+
78
+ it "should have create_child!" do
79
+ @parent.should_receive(:create_child!).with(@attributes)
80
+ @subject.create_child!(@parent_id, @attributes)
81
+ end
82
+
83
+ it "should have update_child" do
84
+ @parent.should_receive(:update_child).with(@child_id, @attributes)
85
+ @subject.update_child(@parent_id, @child_id, @attributes)
86
+ end
87
+
88
+ it "should have destroy_child" do
89
+ @parent.should_receive(:destroy_child).with(@child_id)
90
+ @subject.destroy_child(@parent_id, @child_id)
91
+ end
92
+ end
93
+
94
+ describe "with :except" do
95
+ klass = Class.new do
96
+ extend HasCrudFor
97
+ has_crud_for :items, :except => [:update, :destroy]
98
+ end
99
+
100
+ subject { klass.new }
101
+
102
+ it { should respond_to :find_item }
103
+ it { should respond_to :build_item }
104
+ it { should respond_to :create_item }
105
+ it { should_not respond_to :update_item }
106
+ it { should_not respond_to :destroy_item }
107
+ end
108
+
109
+ describe "with :only" do
110
+ klass = Class.new do
111
+ extend HasCrudFor
112
+ has_crud_for :items, :only => [:find, :build, :create]
113
+ end
114
+
115
+ subject { klass.new }
116
+
117
+ it { should respond_to :find_item }
118
+ it { should respond_to :build_item }
119
+ it { should respond_to :create_item }
120
+ it { should_not respond_to :update_item }
121
+ it { should_not respond_to :destroy_item }
122
+ end
123
+
124
+ describe "with :as" do
125
+ klass = Class.new do
126
+ extend HasCrudFor
127
+ has_crud_for :items, :as => :things
128
+ end
129
+
130
+ subject { klass.new }
131
+
132
+ it { should respond_to :find_thing }
133
+ it { should respond_to :build_thing }
134
+ it { should respond_to :create_thing }
135
+ it { should respond_to :update_thing }
136
+ it { should respond_to :destroy_thing }
137
+ end
138
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: has_crud_for
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jan Dudek
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-11-30 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: &70287765609300 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70287765609300
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &70287765608820 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70287765608820
36
+ - !ruby/object:Gem::Dependency
37
+ name: activesupport
38
+ requirement: &70287765608320 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70287765608320
47
+ - !ruby/object:Gem::Dependency
48
+ name: i18n
49
+ requirement: &70287765607760 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *70287765607760
58
+ description: HasCrudFor is a small meta-programming snippet that adds find_*, build_*,
59
+ create_*, update_* and destroy_* methods intended as a better API for your associations
60
+ email:
61
+ - jd@jandudek.com
62
+ executables: []
63
+ extensions: []
64
+ extra_rdoc_files: []
65
+ files:
66
+ - .gitignore
67
+ - Gemfile
68
+ - MIT-LICENSE
69
+ - README.rdoc
70
+ - Rakefile
71
+ - has_crud_for.gemspec
72
+ - lib/has_crud_for.rb
73
+ - lib/has_crud_for/version.rb
74
+ - spec/has_crud_for_spec.rb
75
+ homepage: ''
76
+ licenses: []
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project: has_crud_for
95
+ rubygems_version: 1.8.7
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: Law of Demeter in ActiveRecord models
99
+ test_files:
100
+ - spec/has_crud_for_spec.rb