merb_datamapper 0.9.2 → 0.9.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +1 -0
- data/Manifest.txt +33 -0
- data/README.txt +13 -0
- data/Rakefile +47 -35
- data/TODO +10 -4
- data/datamapper_generators/migration/USAGE +2 -3
- data/datamapper_generators/migration/migration_generator.rb +6 -6
- data/datamapper_generators/migration/templates/new_migration.erb +3 -3
- data/datamapper_generators/model/model_generator.rb +17 -10
- data/datamapper_generators/model/templates/app/models/%model_file_name%.rb +7 -5
- data/datamapper_generators/resource_controller/resource_controller_generator.rb +62 -27
- data/datamapper_generators/resource_controller/templates/app/controllers/%controller_file_name%.rb +6 -6
- data/datamapper_generators/resource_controller/templates/app/helpers/%controller_file_name%_helper.rb +1 -1
- data/datamapper_generators/resource_controller/templates/app/views/%controller_file_name%/edit.html.erb +19 -1
- data/datamapper_generators/resource_controller/templates/app/views/%controller_file_name%/index.html.erb +22 -1
- data/datamapper_generators/resource_controller/templates/app/views/%controller_file_name%/new.html.erb +18 -1
- data/datamapper_generators/resource_controller/templates/app/views/%controller_file_name%/show.html.erb +12 -1
- data/datamapper_generators/resource_migration/USAGE +4 -0
- data/datamapper_generators/resource_migration/resource_migration_generator.rb +122 -0
- data/datamapper_generators/resource_migration/templates/class_migration.erb +13 -0
- data/lib/merb/orms/data_mapper/connection.rb +61 -26
- data/lib/merb/orms/data_mapper/database.yml.sample +32 -12
- data/lib/merb/orms/data_mapper/resource.rb +12 -0
- data/lib/merb/session/data_mapper_session.rb +47 -40
- data/lib/merb_datamapper.rb +15 -11
- data/lib/merb_datamapper/merbtasks.rb +42 -13
- data/lib/merb_datamapper/version.rb +5 -0
- data/spec/connection_spec.rb +67 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +15 -0
- metadata +58 -45
- data/README +0 -10
- data/lib/merb/orms/data_mapper/base.rb +0 -6
- data/specs/merb_sequel_spec.rb +0 -0
- data/specs/spec_helper.rb +0 -2
@@ -1,3 +1,21 @@
|
|
1
1
|
<h1><%= full_controller_const %> controller, edit action</h1>
|
2
2
|
|
3
|
-
<p>Edit this file in <tt>app/views/<%= controller_file_name %>/edit.html.erb</tt></p>
|
3
|
+
<p>Edit this file in <tt>app/views/<%= controller_file_name %>/edit.html.erb</tt></p>
|
4
|
+
|
5
|
+
<%%= error_messages_for :<%= singular_model %> %>
|
6
|
+
|
7
|
+
<%% form_for(@<%= singular_model %>, :action => url(:<%= singular_model %>, @<%= singular_model %>)) do %>
|
8
|
+
<% for property in properties.select{|p| !p.key?} -%>
|
9
|
+
<p>
|
10
|
+
<b><%= Extlib::Inflection.humanize(property.field) %></b><br />
|
11
|
+
<%%= <%= field_from_type(property.type) %> :<%= property.getter %> %>
|
12
|
+
</p>
|
13
|
+
|
14
|
+
<% end -%>
|
15
|
+
<p>
|
16
|
+
<%%= submit_button "Update" %>
|
17
|
+
</p>
|
18
|
+
<%% end %>
|
19
|
+
|
20
|
+
<%%= link_to 'Show', url(:<%= singular_model %>, @<%= singular_model %>) %> |
|
21
|
+
<%%= link_to 'Back', url(:<%= plural_model %>) %>
|
@@ -1,3 +1,24 @@
|
|
1
1
|
<h1><%= full_controller_const %> controller, index action</h1>
|
2
2
|
|
3
|
-
<p>Edit this file in <tt>app/views/<%= controller_file_name %>/index.html.erb</tt></p>
|
3
|
+
<p>Edit this file in <tt>app/views/<%= controller_file_name %>/index.html.erb</tt></p>
|
4
|
+
|
5
|
+
<table>
|
6
|
+
<tr>
|
7
|
+
<% for property in properties.reject{|p| p.lazy?} -%>
|
8
|
+
<th><%= Extlib::Inflection.humanize(property.field) %></th>
|
9
|
+
<% end -%>
|
10
|
+
</tr>
|
11
|
+
|
12
|
+
<%% for <%= singular_model %> in @<%= plural_model %> %>
|
13
|
+
<tr>
|
14
|
+
<% for property in properties.reject{|p| p.lazy?} -%>
|
15
|
+
<td><%%=h <%= singular_model %>.<%= property.getter %> %></td>
|
16
|
+
<% end -%>
|
17
|
+
<td><%%= link_to 'Show', url(:<%= singular_model %>, <%= singular_model %>) %></td>
|
18
|
+
<td><%%= link_to 'Edit', url(:edit_<%= singular_model %>, <%= singular_model %>) %></td>
|
19
|
+
<td><%%= delete_button :<%= singular_model %>, <%= singular_model %> %></td>
|
20
|
+
</tr>
|
21
|
+
<%% end %>
|
22
|
+
</table>
|
23
|
+
|
24
|
+
<%%= link_to 'New', url(:new_<%= singular_model %>) %>
|
@@ -1,3 +1,20 @@
|
|
1
1
|
<h1><%= full_controller_const %> controller, new action</h1>
|
2
2
|
|
3
|
-
<p>Edit this file in <tt>app/views/<%= controller_file_name %>/new.html.erb</tt></p>
|
3
|
+
<p>Edit this file in <tt>app/views/<%= controller_file_name %>/new.html.erb</tt></p>
|
4
|
+
|
5
|
+
<%%= error_messages_for :<%= singular_model %> %>
|
6
|
+
|
7
|
+
<%% form_for(@<%= singular_model %>, :action => url(:<%= plural_model %>) ) do |f| %>
|
8
|
+
<% for property in properties.select{|p| !p.key?} -%>
|
9
|
+
<p>
|
10
|
+
<b><%= Extlib::Inflection.humanize(property.field) %></b><br />
|
11
|
+
<%%= <%= field_from_type(property.type) %> :<%= property.getter %> %>
|
12
|
+
</p>
|
13
|
+
|
14
|
+
<% end -%>
|
15
|
+
<p>
|
16
|
+
<%%= submit_button "Create" %>
|
17
|
+
</p>
|
18
|
+
<%% end %>
|
19
|
+
|
20
|
+
<%%= link_to 'Back', url(:<%= plural_model %>) %>
|
@@ -1,3 +1,14 @@
|
|
1
1
|
<h1><%= full_controller_const %> controller, show action</h1>
|
2
2
|
|
3
|
-
<p>Edit this file in <tt>app/views/<%= controller_file_name %>/show.html.erb</tt></p>
|
3
|
+
<p>Edit this file in <tt>app/views/<%= controller_file_name %>/show.html.erb</tt></p>
|
4
|
+
|
5
|
+
<% for property in properties -%>
|
6
|
+
<p>
|
7
|
+
<b><%= Extlib::Inflection.humanize(property.field) %>:</b>
|
8
|
+
<%%=h @<%= singular_model %>.<%= property.getter %> %>
|
9
|
+
</p>
|
10
|
+
|
11
|
+
<% end -%>
|
12
|
+
|
13
|
+
<%%= link_to 'Edit', url(:edit_<%= singular_model %>, @<%= singular_model %>) %> |
|
14
|
+
<%%= link_to 'Back', url(:<%= plural_model %>) %>
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# require 'merb'
|
2
|
+
class ResourceMigrationGenerator < RubiGen::Base
|
3
|
+
|
4
|
+
# these define datamapper specific properties, not general database concepts
|
5
|
+
UNWANTED_PROPERTIES = [:public, :protected, :private, :accessor,
|
6
|
+
:reader, :writer, :lazy, :lock, :field, :ordinal,
|
7
|
+
:track, :auto_validation, :validates]
|
8
|
+
|
9
|
+
default_options :author => nil
|
10
|
+
|
11
|
+
attr_reader :name, :klass
|
12
|
+
|
13
|
+
def initialize(runtime_args, runtime_options = {})
|
14
|
+
super
|
15
|
+
usage if args.empty?
|
16
|
+
@name = args.shift
|
17
|
+
extract_options
|
18
|
+
end
|
19
|
+
|
20
|
+
def manifest
|
21
|
+
unless @name
|
22
|
+
puts banner
|
23
|
+
exit 1
|
24
|
+
end
|
25
|
+
|
26
|
+
# first see if we can find our model file where it should be!
|
27
|
+
model_file = File.join(Dir.pwd, "app/models","#{@name.snake_case}.rb")
|
28
|
+
unless File.exist?(model_file)
|
29
|
+
puts "Couldn't find the model file for #{@name}"
|
30
|
+
exit 1
|
31
|
+
end
|
32
|
+
|
33
|
+
# next, check we actually have a class!
|
34
|
+
require model_file
|
35
|
+
@klass = Module.const_get(@name.camel_case)
|
36
|
+
if @klass.nil?
|
37
|
+
puts "File didn't seem to include the model #{@name.camel_case}"
|
38
|
+
exit 1
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
record do |m|
|
45
|
+
# Ensure appropriate folders exists
|
46
|
+
m.directory 'schema/migrations'
|
47
|
+
|
48
|
+
@migration_name = "create_%s_table" % @name.snake_case.pluralize
|
49
|
+
|
50
|
+
filename = format("%03d_%s", (highest_migration+1), @migration_name)
|
51
|
+
|
52
|
+
m.template "class_migration.erb", "schema/migrations/#{filename}.rb",
|
53
|
+
:assigns => {
|
54
|
+
:migration_name => @migration_name ,
|
55
|
+
:number => (highest_migration+1),
|
56
|
+
:klass_name => klass.storage_name,
|
57
|
+
:properties => properties_as_strings
|
58
|
+
}
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
def banner
|
65
|
+
<<-EOS
|
66
|
+
Creates a new migration for merb using DataMapper
|
67
|
+
|
68
|
+
USAGE: #{$0} #{spec.name} ResourceClass
|
69
|
+
|
70
|
+
Example:
|
71
|
+
#{$0} #{spec.name} Post
|
72
|
+
|
73
|
+
If you already have 3 migrations, this will create the Post migration in
|
74
|
+
schema/migration/004_create_posts_table.rb
|
75
|
+
|
76
|
+
NB: Currently the generator doesn't make any columns for 'belongs_to'-type
|
77
|
+
associations.
|
78
|
+
EOS
|
79
|
+
end
|
80
|
+
|
81
|
+
def add_options!(opts)
|
82
|
+
# opts.separator ''
|
83
|
+
# opts.separator 'Options:'
|
84
|
+
# For each option below, place the default
|
85
|
+
# at the top of the file next to "default_options"
|
86
|
+
# opts.on("-a", "--author=\"Your Name\"", String,
|
87
|
+
# "Some comment about this option",
|
88
|
+
# "Default: none") { |options[:author]| }
|
89
|
+
# opts.on("-v", "--version", "Show the #{File.basename($0)} version number and quit.")
|
90
|
+
end
|
91
|
+
|
92
|
+
def extract_options
|
93
|
+
# for each option, extract it into a local variable (and create an "attr_reader :author" at the top)
|
94
|
+
# Templates can access these value via the attr_reader-generated methods, but not the
|
95
|
+
# raw instance variable value.
|
96
|
+
# @author = options[:author]
|
97
|
+
end
|
98
|
+
|
99
|
+
def highest_migration
|
100
|
+
@highest_migration ||= Dir[Dir.pwd+'/schema/migrations/*'].map{ |f|
|
101
|
+
File.basename(f) =~ /^(\d+)/
|
102
|
+
$1}.max.to_i
|
103
|
+
end
|
104
|
+
|
105
|
+
def property_as_string(p)
|
106
|
+
name = p.field
|
107
|
+
type = p.type.to_s
|
108
|
+
# clear out non-db related properties
|
109
|
+
options = p.options.reject { |key, value| UNWANTED_PROPERTIES.include? key }
|
110
|
+
options_as_array = []
|
111
|
+
options.each do |key, value|
|
112
|
+
options_as_array << ":#{key} => #{value}"
|
113
|
+
end
|
114
|
+
|
115
|
+
(options_as_array.empty?) ? ":#{name}, #{type}" :
|
116
|
+
":#{name}, #{type}, #{options_as_array.join(', ')}"
|
117
|
+
end
|
118
|
+
|
119
|
+
def properties_as_strings
|
120
|
+
@properties_as_strings ||= klass.properties.map {|p| property_as_string(p) }
|
121
|
+
end
|
122
|
+
end
|
@@ -1,40 +1,33 @@
|
|
1
1
|
require 'fileutils'
|
2
|
-
require 'data_mapper'
|
3
2
|
|
4
3
|
module Merb
|
5
4
|
module Orms
|
6
5
|
module DataMapper
|
7
6
|
class << self
|
8
|
-
def config_file() Merb.
|
9
|
-
def sample_dest() Merb.
|
7
|
+
def config_file() Merb.dir_for(:config) / "database.yml" end
|
8
|
+
def sample_dest() Merb.dir_for(:config) / "database.yml.sample" end
|
10
9
|
def sample_source() File.dirname(__FILE__) / "database.yml.sample" end
|
11
|
-
|
10
|
+
|
12
11
|
def copy_sample_config
|
13
12
|
FileUtils.cp sample_source, sample_dest unless File.exists?(sample_dest)
|
14
13
|
end
|
15
|
-
|
14
|
+
|
15
|
+
def full_config
|
16
|
+
@full_config ||= Erubis.load_yaml_file(config_file)
|
17
|
+
end
|
18
|
+
|
16
19
|
def config
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
config = (Merb::Plugins.config[:merb_datamapper] = {})
|
22
|
-
(full_config[Merb.environment.to_sym] || full_config[Merb.environment]).each do |k, v|
|
23
|
-
if k == 'port'
|
24
|
-
config[k.to_sym] = v.to_i
|
25
|
-
else
|
26
|
-
config[k.to_sym] = v
|
27
|
-
end
|
28
|
-
end
|
29
|
-
config
|
30
|
-
end
|
20
|
+
if !Merb::Plugins.config[:merb_datamapper].nil? && Merb::Plugins.config[:merb_datamapper].empty?
|
21
|
+
Merb::Plugins.config[:merb_datamapper] = get_config_for_environment
|
22
|
+
end
|
23
|
+
@config ||= Merb::Plugins.config[:merb_datamapper] ||= get_config_for_environment
|
31
24
|
end
|
32
|
-
|
25
|
+
|
33
26
|
# Database connects as soon as the gem is loaded
|
34
27
|
def connect
|
35
28
|
if File.exists?(config_file)
|
36
|
-
|
37
|
-
|
29
|
+
start_logging
|
30
|
+
setup_connections
|
38
31
|
else
|
39
32
|
copy_sample_config
|
40
33
|
Merb.logger.error! "No database.yml file found in #{Merb.root}/config."
|
@@ -42,15 +35,57 @@ module Merb
|
|
42
35
|
exit(1)
|
43
36
|
end
|
44
37
|
end
|
45
|
-
|
38
|
+
|
39
|
+
def start_logging
|
40
|
+
::DataMapper.logger = Merb.logger
|
41
|
+
::DataMapper.logger.info("Connecting to database...")
|
42
|
+
end
|
43
|
+
|
44
|
+
def setup_connections
|
45
|
+
conf = config.dup
|
46
|
+
repositories = conf.delete(:repositories)
|
47
|
+
::DataMapper.setup(:default, conf) unless conf.empty?
|
48
|
+
repositories.each { |name, opts| ::DataMapper.setup(name, opts) } if repositories
|
49
|
+
end
|
50
|
+
|
46
51
|
# Registering this ORM lets the user choose DataMapper as a session store
|
47
52
|
# in merb.yml's session_store: option.
|
48
53
|
def register_session_type
|
49
54
|
Merb.register_session_type("datamapper",
|
50
|
-
|
51
|
-
|
55
|
+
"merb/session/data_mapper_session",
|
56
|
+
"Using DataMapper database sessions")
|
57
|
+
end
|
58
|
+
|
59
|
+
def symbolize_keys(h)
|
60
|
+
config = {}
|
61
|
+
|
62
|
+
h.each do |k, v|
|
63
|
+
if k == 'port'
|
64
|
+
config[k.to_sym] = v.to_i
|
65
|
+
elsif k == 'adapter' && v == 'postgresql'
|
66
|
+
config[k.to_sym] = 'postgres'
|
67
|
+
elsif v.is_a?(Hash)
|
68
|
+
config[k.to_sym] = symbolize_keys(v)
|
69
|
+
else
|
70
|
+
config[k.to_sym] = v
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
config
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def get_config_for_environment
|
80
|
+
if hash = full_config[Merb.environment]
|
81
|
+
symbolize_keys(hash)
|
82
|
+
elsif hash = full_config[Merb.environment.to_sym]
|
83
|
+
hash
|
84
|
+
else
|
85
|
+
raise ArgumentError, "missing environment '#{Merb.environment}' in config file #{config_file}"
|
86
|
+
end
|
52
87
|
end
|
53
88
|
end
|
54
89
|
end
|
55
90
|
end
|
56
|
-
end
|
91
|
+
end
|
@@ -1,16 +1,36 @@
|
|
1
1
|
---
|
2
2
|
# This is a sample database file for the DataMapper ORM
|
3
|
-
|
4
|
-
:
|
5
|
-
:
|
6
|
-
:
|
7
|
-
:
|
8
|
-
:
|
3
|
+
development: &defaults
|
4
|
+
# These are the settings for repository :default
|
5
|
+
adapter: postgres
|
6
|
+
database: sample_development
|
7
|
+
username: the_user
|
8
|
+
password: secrets
|
9
|
+
host: localhost
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
:
|
11
|
+
# Add more repositories
|
12
|
+
# repositories:
|
13
|
+
# repo1:
|
14
|
+
# adapter: postgresql
|
15
|
+
# database: sample_development
|
16
|
+
# username: the_user
|
17
|
+
# password: secrets
|
18
|
+
# host: localhost
|
19
|
+
# repo2:
|
20
|
+
# ...
|
13
21
|
|
14
|
-
:
|
15
|
-
<<:
|
16
|
-
|
22
|
+
test:
|
23
|
+
<<: *defaults
|
24
|
+
database: sample_test
|
25
|
+
|
26
|
+
# repositories:
|
27
|
+
# repo1:
|
28
|
+
# database: sample_development
|
29
|
+
|
30
|
+
production:
|
31
|
+
<<: *defaults
|
32
|
+
database: sample_production
|
33
|
+
|
34
|
+
# repositories:
|
35
|
+
# repo1:
|
36
|
+
# database: sample_development
|
@@ -1,4 +1,10 @@
|
|
1
|
-
|
1
|
+
begin
|
2
|
+
gem 'dm-core', '=0.9.3'
|
3
|
+
require 'dm-core'
|
4
|
+
rescue LoadError => e
|
5
|
+
require 'data_mapper'
|
6
|
+
end
|
7
|
+
|
2
8
|
require 'base64'
|
3
9
|
module Merb
|
4
10
|
module SessionMixin
|
@@ -20,27 +26,31 @@ module Merb
|
|
20
26
|
end
|
21
27
|
|
22
28
|
table_name = (Merb::Plugins.config[:merb_datamapper][:session_table_name] || "sessions")
|
23
|
-
|
24
|
-
class DataMapperSession
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
property :
|
29
|
-
property :
|
30
|
-
|
29
|
+
|
30
|
+
class DataMapperSession
|
31
|
+
include DataMapper::Resource
|
32
|
+
|
33
|
+
storage_names[:default] = "sessions"
|
34
|
+
property :session_id, String, :length => 255, :lazy => false, :key => true
|
35
|
+
property :data, Text, :lazy => false
|
36
|
+
property :updated_at, DateTime
|
37
|
+
|
31
38
|
attr_accessor :needs_new_cookie
|
32
|
-
|
39
|
+
|
33
40
|
class << self
|
34
41
|
# Generates a new session ID and creates a row for the new session in the database.
|
35
42
|
def generate
|
36
|
-
|
43
|
+
new_session = self.new(:data =>{})
|
44
|
+
new_session.session_id = Merb::SessionMixin::rand_uuid
|
45
|
+
new_session.save
|
46
|
+
new_session
|
37
47
|
end
|
38
|
-
|
48
|
+
|
39
49
|
# Gets the existing session based on the <tt>session_id</tt> available in cookies.
|
40
50
|
# If none is found, generates a new session.
|
41
51
|
def persist(session_id)
|
42
|
-
if session_id
|
43
|
-
session = self
|
52
|
+
if !session_id.blank?
|
53
|
+
session = self.first :session_id => session_id
|
44
54
|
end
|
45
55
|
unless session
|
46
56
|
session = generate
|
@@ -51,62 +61,59 @@ module Merb
|
|
51
61
|
def marshal(data) Base64.encode64(Marshal.dump(data)) if data end
|
52
62
|
def unmarshal(data) Marshal.load(Base64.decode64(data)) if data end
|
53
63
|
end
|
54
|
-
|
64
|
+
|
55
65
|
# Regenerate the Session ID
|
56
66
|
def regenerate
|
57
67
|
self.session_id = Merb::SessionMixin::rand_uuid
|
58
68
|
self.needs_new_cookie = true
|
59
69
|
self.save
|
60
|
-
end
|
61
|
-
|
62
|
-
# Recreates the cookie with the default expiration time
|
63
|
-
# Useful during log in for pushing back the expiration date
|
70
|
+
end
|
71
|
+
|
72
|
+
# Recreates the cookie with the default expiration time
|
73
|
+
# Useful during log in for pushing back the expiration date
|
64
74
|
def refresh_expiration
|
65
75
|
self.needs_new_cookie = true
|
66
76
|
end
|
67
|
-
|
68
|
-
# Lazy-delete of session data
|
77
|
+
|
78
|
+
# Lazy-delete of session data
|
69
79
|
def delete(key = nil)
|
70
80
|
key ? self.data.delete(key) : self.data.clear
|
71
81
|
end
|
72
|
-
|
82
|
+
|
73
83
|
def empty?
|
74
84
|
data.empty?
|
75
85
|
end
|
76
|
-
|
86
|
+
|
77
87
|
def each(&b)
|
78
88
|
data.each(&b)
|
79
89
|
end
|
80
|
-
|
90
|
+
|
91
|
+
def each_with_index(&b)
|
92
|
+
data.each_with_index(&b)
|
93
|
+
end
|
94
|
+
|
81
95
|
def [](key)
|
82
96
|
data[key]
|
83
97
|
end
|
84
|
-
|
98
|
+
|
85
99
|
def []=(key, val)
|
86
100
|
data[key] = val
|
87
101
|
end
|
88
|
-
|
102
|
+
|
89
103
|
def data
|
90
|
-
@unmarshalled_data
|
104
|
+
@unmarshalled_data ||= self.class.unmarshal(@data) || {}
|
91
105
|
end
|
92
|
-
|
106
|
+
|
93
107
|
def data=(data)
|
94
108
|
@data, @unmarshalled_data = data, data
|
95
109
|
end
|
96
|
-
|
110
|
+
|
97
111
|
private
|
98
|
-
|
99
|
-
|
100
|
-
|
112
|
+
|
113
|
+
before :save, :serialize_data
|
114
|
+
|
101
115
|
def serialize_data
|
102
|
-
|
116
|
+
attribute_set :data, self.class.marshal(self.data)
|
103
117
|
end
|
104
118
|
end
|
105
|
-
|
106
|
-
|
107
|
-
unless DataMapper.database.table_exists?(table_name)
|
108
|
-
puts "Warning: The database did not contain a '#{table_name}' table for sessions."
|
109
|
-
DataMapperSession.auto_migrate!
|
110
|
-
puts "Created sessions table."
|
111
|
-
end
|
112
119
|
end
|