learn_rails 0.0.0 → 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/.coveralls.yml +1 -0
- data/.gitignore +19 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +143 -0
- data/Rakefile +16 -0
- data/bin/learn +4 -0
- data/features/accessors.feature +122 -0
- data/features/associations.feature +506 -0
- data/features/step_definitions/associations.rb +7 -0
- data/features/support/env.rb +3 -0
- data/features/support/setup.rb +4 -0
- data/learn_rails.gemspec +31 -0
- data/lib/ext/hash.rb +5 -0
- data/lib/learn_rails.rb +54 -3
- data/lib/learn_rails/accessors.rb +56 -0
- data/lib/learn_rails/associations.rb +44 -0
- data/lib/learn_rails/associations/belongs_to.rb +48 -0
- data/lib/learn_rails/associations/has_many.rb +13 -0
- data/lib/learn_rails/associations/has_one.rb +52 -0
- data/lib/learn_rails/cli.rb +11 -0
- data/lib/learn_rails/version.rb +3 -0
- data/spec/learn_rails/accessors_spec.rb +142 -0
- data/spec/learn_rails/associations_spec.rb +575 -0
- data/spec/spec_helper.rb +4 -0
- metadata +197 -11
data/learn_rails.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'learn_rails/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "learn_rails"
|
8
|
+
spec.version = LearnRails::VERSION
|
9
|
+
spec.authors = ["Peter-Jan Celis"]
|
10
|
+
spec.email = ["pj@celis.org"]
|
11
|
+
spec.description = %q{Gem learn_rails shows you the ruby code behind rails magic.}
|
12
|
+
spec.summary = %q{Gem learn_rails shows you the ruby code behind rails magic.}
|
13
|
+
spec.homepage = "http://github.com/pjc/learn_rails"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "activesupport", "~> 4.0.1"
|
22
|
+
spec.add_dependency "thor", "~> 0.18.1"
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
spec.add_development_dependency "rspec", "~> 2.14.1"
|
27
|
+
spec.add_development_dependency "cucumber", "~> 1.3.9"
|
28
|
+
spec.add_development_dependency "aruba", "~> 0.5.3"
|
29
|
+
spec.add_development_dependency "debugger", "~> 1.6.2"
|
30
|
+
spec.add_development_dependency "coveralls", "~> 0.7.0"
|
31
|
+
end
|
data/lib/ext/hash.rb
ADDED
data/lib/learn_rails.rb
CHANGED
@@ -1,3 +1,54 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require "learn_rails/version"
|
2
|
+
require "ext/hash"
|
3
|
+
require "learn_rails/associations"
|
4
|
+
require "learn_rails/associations/belongs_to"
|
5
|
+
require "learn_rails/associations/has_one"
|
6
|
+
require "learn_rails/associations/has_many"
|
7
|
+
require "learn_rails/accessors"
|
8
|
+
require "active_support/core_ext/string"
|
9
|
+
|
10
|
+
module LearnRails
|
11
|
+
def self.analyze(*magic)
|
12
|
+
if accessor? magic
|
13
|
+
remove_model_name_from_accessor magic
|
14
|
+
LearnRails::Accessors.code_for magic
|
15
|
+
elsif association? magic
|
16
|
+
ensure_model_name_for_association magic
|
17
|
+
LearnRails::Associations.code_for magic
|
18
|
+
else
|
19
|
+
error_message
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def self.accessor? magic
|
26
|
+
(magic[0..1] & ['attr_reader', 'attr_writer', 'attr_accessor']).any?
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.remove_model_name_from_accessor magic
|
30
|
+
magic.shift unless ['attr_reader', 'attr_writer', 'attr_accessor'].include? magic[0]
|
31
|
+
magic
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.association? magic
|
35
|
+
(magic[0..1] & ['belongs_to', 'has_one', 'has_many']).any?
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.ensure_model_name_for_association magic
|
39
|
+
if ['has_one', 'has_many'].include? magic[0]
|
40
|
+
puts "What is the model name for this association?"
|
41
|
+
model_name = $stdin.gets.strip
|
42
|
+
magic.unshift model_name
|
43
|
+
elsif magic[0] == 'belongs_to'
|
44
|
+
magic.unshift 'token value for params[:model]'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.error_message
|
49
|
+
<<-error.gsub(/^\s+/, '')
|
50
|
+
No ruby code available.
|
51
|
+
See http://www.github.com/pjc/learn_rails for list of valid instructions.
|
52
|
+
error
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module LearnRails
|
2
|
+
class Accessors
|
3
|
+
def self.code_for(accessor)
|
4
|
+
@accessor = accessor
|
5
|
+
@code = <<-code.gsub(/^\s+/, '')
|
6
|
+
code
|
7
|
+
|
8
|
+
attributes.each do |attribute|
|
9
|
+
@code << getter_method_for(attribute) if getter_method_needed?
|
10
|
+
@code << setter_method_for(attribute) if setter_method_needed?
|
11
|
+
end
|
12
|
+
|
13
|
+
@code
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def self.attributes
|
19
|
+
@accessor.drop(1).map { |attr| attr.delete(',').delete(':') }.delete_if(&:empty?)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.getter_method_needed?
|
23
|
+
@getter ||= ['reader', 'accessor'].include? accessor_type
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.setter_method_needed?
|
27
|
+
@setter ||= ['writer', 'accessor'].include? accessor_type
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.accessor_type
|
31
|
+
@accessor[0].split('_')[1]
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.getter_method_for attribute
|
35
|
+
<<-code.gsub(/^\s+/, '')
|
36
|
+
#{empty_comment_line_if_needed}
|
37
|
+
# def #{attribute}
|
38
|
+
# @#{attribute}
|
39
|
+
# end
|
40
|
+
code
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.setter_method_for attribute
|
44
|
+
<<-code.gsub(/^\s+/, '')
|
45
|
+
#{empty_comment_line_if_needed}
|
46
|
+
# def #{attribute}=(value)
|
47
|
+
# @#{attribute} = value
|
48
|
+
# end
|
49
|
+
code
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.empty_comment_line_if_needed
|
53
|
+
@code.present? ? '#' : nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module LearnRails
|
2
|
+
class Associations
|
3
|
+
def self.code_for(association)
|
4
|
+
params = params association
|
5
|
+
"LearnRails::Associations::#{params[:association].camelize}".constantize.send(:code_for, params)
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def self.params association
|
11
|
+
clean_up association
|
12
|
+
hashify_conditions_options association
|
13
|
+
|
14
|
+
params = {}
|
15
|
+
params[:model] = association.shift.downcase
|
16
|
+
params[:association] = association.shift
|
17
|
+
params[:associate] = association.shift
|
18
|
+
|
19
|
+
options_specified = Hash[*association].symbolize_keys!
|
20
|
+
|
21
|
+
params.merge!(options_specified)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.clean_up association
|
25
|
+
association.delete "=>"
|
26
|
+
association.map! { |e| e.delete(':').delete(',').delete('\"') }
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.hashify_conditions_options association
|
30
|
+
return association unless association.include? "conditions"
|
31
|
+
|
32
|
+
start_options_index = association.index("conditions") + 1
|
33
|
+
end_options_index = association[start_options_index..-1].find_index { |e| e.match /}/ } + start_options_index
|
34
|
+
|
35
|
+
conditions = []
|
36
|
+
association[start_options_index..end_options_index].each do |option|
|
37
|
+
conditions << option.delete('{').delete('}') if option.length > 1
|
38
|
+
association.delete(option)
|
39
|
+
end
|
40
|
+
|
41
|
+
association.insert(start_options_index, Hash[*conditions])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module LearnRails
|
2
|
+
class Associations::BelongsTo < Associations
|
3
|
+
def self.code_for(params)
|
4
|
+
associate_model = (params[:class_name] || params[:associate]).camelize
|
5
|
+
foreign_id = params[:foreign_key] || params[:associate] + "_id"
|
6
|
+
primary_id = params[:primary_key] || "id"
|
7
|
+
|
8
|
+
<<-code.gsub(/^\s+/, '')
|
9
|
+
# def #{params[:associate]}(force_reload = false)
|
10
|
+
# @#{params[:associate]} = nil if force_reload
|
11
|
+
# @#{params[:associate]} ||= #{finder_method params, foreign_id, associate_model}
|
12
|
+
# end
|
13
|
+
#{ setter_method(params, foreign_id, primary_id) unless params[:readonly] }
|
14
|
+
#
|
15
|
+
# def build_#{params[:associate]}(attributes = {})
|
16
|
+
# self.#{params[:associate]} = #{associate_model}.new(attributes)
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# def create_#{params[:associate]}(attributes = {})
|
20
|
+
# self.#{params[:associate]} = #{associate_model}.create(attributes)
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# def create_#{params[:associate]}!(attributes = {})
|
24
|
+
# self.#{params[:associate]} = #{associate_model}.create!(attributes)
|
25
|
+
# end
|
26
|
+
code
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def self.setter_method params, foreign_id, primary_id
|
32
|
+
<<-code.gsub(/^\s+/, '')
|
33
|
+
#
|
34
|
+
# def #{params[:associate]}=(#{params[:associate]})
|
35
|
+
# self.#{foreign_id} = #{params[:associate]}.#{primary_id}
|
36
|
+
# end
|
37
|
+
code
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.finder_method params, foreign_id, associate_model
|
41
|
+
if params[:conditions]
|
42
|
+
"#{associate_model}.first(:conditions => {:id => self.#{foreign_id}, #{params[:conditions].to_condition_string}})"
|
43
|
+
else
|
44
|
+
"#{associate_model}.find_by_id(self.#{foreign_id})"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module LearnRails
|
2
|
+
class Associations::HasMany < Associations
|
3
|
+
def self.code_for(params)
|
4
|
+
associate_model = params[:associate].singularize.camelize
|
5
|
+
|
6
|
+
<<-code.gsub(/^\s+/, '')
|
7
|
+
# def #{params[:associate]}
|
8
|
+
# #{associate_model}.where(#{params[:model]}_id: self.id)
|
9
|
+
# end
|
10
|
+
code
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module LearnRails
|
2
|
+
class Associations::HasOne < Associations
|
3
|
+
def self.code_for(params)
|
4
|
+
associate_model = (params[:class_name] || params[:associate]).camelize
|
5
|
+
foreign_id = params[:foreign_key] || params[:model] + "_id"
|
6
|
+
primary_id = params[:primary_key] || "id"
|
7
|
+
|
8
|
+
<<-code.gsub(/^\s+/, '')
|
9
|
+
# def #{params[:associate]}(force_reload = false)
|
10
|
+
# @#{params[:associate]} = nil if force_reload
|
11
|
+
# @#{params[:associate]} ||= #{finder_method params, foreign_id, primary_id, associate_model}
|
12
|
+
# end
|
13
|
+
#{ setter_method(params, foreign_id, primary_id) unless params[:readonly] }
|
14
|
+
#
|
15
|
+
# def build_#{params[:associate]}(attributes = {})
|
16
|
+
# attributes[:#{foreign_id}] = self.#{primary_id}
|
17
|
+
# #{associate_model}.new(attributes)
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# def create_#{params[:associate]}(attributes = {})
|
21
|
+
# attributes[:#{foreign_id}] = self.#{primary_id}
|
22
|
+
# #{associate_model}.create(attributes)
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# def create_#{params[:associate]}!(attributes = {})
|
26
|
+
# attributes[:#{foreign_id}] = self.#{primary_id}
|
27
|
+
# #{associate_model}.create!(attributes)
|
28
|
+
# end
|
29
|
+
code
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def self.setter_method params, foreign_id, primary_id
|
35
|
+
<<-code.gsub(/^\s+/, '')
|
36
|
+
#
|
37
|
+
# def #{params[:associate]}=(#{params[:associate]})
|
38
|
+
# #{params[:associate]}.#{foreign_id} = self.#{primary_id}
|
39
|
+
# #{params[:associate]}.save
|
40
|
+
# end
|
41
|
+
code
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.finder_method params, foreign_id, primary_id, associate_model
|
45
|
+
if params[:conditions]
|
46
|
+
"#{associate_model}.first(:conditions => {:#{foreign_id} => self.#{primary_id}, #{params[:conditions].to_condition_string}})"
|
47
|
+
else
|
48
|
+
"#{associate_model}.find_by_#{foreign_id}(self.#{primary_id})"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
@accessors
|
4
|
+
describe LearnRails::Accessors do
|
5
|
+
|
6
|
+
after(@accessors) do
|
7
|
+
LearnRails::Accessors.instance_variable_set(:@getter, nil)
|
8
|
+
LearnRails::Accessors.instance_variable_set(:@setter, nil)
|
9
|
+
end
|
10
|
+
|
11
|
+
context "attr" do
|
12
|
+
context "reader" do
|
13
|
+
context "with one attribute" do
|
14
|
+
it "should return the correct code" do
|
15
|
+
LearnRails::Accessors.code_for(%w(attr_reader :name)).should eql attr_reader_code
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "with multiple attributes" do
|
20
|
+
it "should return the correct code" do
|
21
|
+
LearnRails::Accessors.code_for(%w(attr_reader :name, :another)).should eql attr_reader_two_attributes_code
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "writer" do
|
27
|
+
context "with one attribute" do
|
28
|
+
it "should return the correct code" do
|
29
|
+
LearnRails::Accessors.code_for(%w(attr_writer :name)).should eql attr_writer_code
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "with multiple attributes" do
|
34
|
+
it "should return the correct code" do
|
35
|
+
LearnRails::Accessors.code_for(%w(attr_writer :name, :another)).should eql attr_writer_two_attributes_code
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "accessor" do
|
41
|
+
context "with one attribute" do
|
42
|
+
it "should return the correct code" do
|
43
|
+
LearnRails::Accessors.code_for(%w(attr_accessor :name)).should eql attr_accessor_code
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "with multiple attributes" do
|
48
|
+
it "should return the correct code" do
|
49
|
+
LearnRails::Accessors.code_for(%w(attr_accessor :name, :another)).should eql attr_accessor_two_attributes_code
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "with comma" do
|
56
|
+
context "right after the last attribute" do
|
57
|
+
it "should return the correct code" do
|
58
|
+
LearnRails::Accessors.code_for(%w(attr_accessor :name,)).should eql attr_accessor_code
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "seperated by a space" do
|
63
|
+
it "should return the correct code" do
|
64
|
+
LearnRails::Accessors.code_for(%w(attr_accessor :name ,)).should eql attr_accessor_code
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def attr_reader_code
|
72
|
+
<<-code.gsub(/^\s+/, '')
|
73
|
+
# def name
|
74
|
+
# @name
|
75
|
+
# end
|
76
|
+
code
|
77
|
+
end
|
78
|
+
|
79
|
+
def attr_writer_code
|
80
|
+
<<-code.gsub(/^\s+/, '')
|
81
|
+
# def name=(value)
|
82
|
+
# @name = value
|
83
|
+
# end
|
84
|
+
code
|
85
|
+
end
|
86
|
+
|
87
|
+
def attr_accessor_code
|
88
|
+
<<-code.gsub(/^\s+/, '')
|
89
|
+
# def name
|
90
|
+
# @name
|
91
|
+
# end
|
92
|
+
#
|
93
|
+
# def name=(value)
|
94
|
+
# @name = value
|
95
|
+
# end
|
96
|
+
code
|
97
|
+
end
|
98
|
+
|
99
|
+
def attr_reader_two_attributes_code
|
100
|
+
<<-code.gsub(/^\s+/, '')
|
101
|
+
# def name
|
102
|
+
# @name
|
103
|
+
# end
|
104
|
+
#
|
105
|
+
# def another
|
106
|
+
# @another
|
107
|
+
# end
|
108
|
+
code
|
109
|
+
end
|
110
|
+
|
111
|
+
def attr_writer_two_attributes_code
|
112
|
+
<<-code.gsub(/^\s+/, '')
|
113
|
+
# def name=(value)
|
114
|
+
# @name = value
|
115
|
+
# end
|
116
|
+
#
|
117
|
+
# def another=(value)
|
118
|
+
# @another = value
|
119
|
+
# end
|
120
|
+
code
|
121
|
+
end
|
122
|
+
|
123
|
+
def attr_accessor_two_attributes_code
|
124
|
+
<<-code.gsub(/^\s+/, '')
|
125
|
+
# def name
|
126
|
+
# @name
|
127
|
+
# end
|
128
|
+
#
|
129
|
+
# def name=(value)
|
130
|
+
# @name = value
|
131
|
+
# end
|
132
|
+
#
|
133
|
+
# def another
|
134
|
+
# @another
|
135
|
+
# end
|
136
|
+
#
|
137
|
+
# def another=(value)
|
138
|
+
# @another = value
|
139
|
+
# end
|
140
|
+
code
|
141
|
+
end
|
142
|
+
end
|