has_crud_for 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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