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.
Files changed (35) hide show
  1. data/History.txt +1 -0
  2. data/Manifest.txt +33 -0
  3. data/README.txt +13 -0
  4. data/Rakefile +47 -35
  5. data/TODO +10 -4
  6. data/datamapper_generators/migration/USAGE +2 -3
  7. data/datamapper_generators/migration/migration_generator.rb +6 -6
  8. data/datamapper_generators/migration/templates/new_migration.erb +3 -3
  9. data/datamapper_generators/model/model_generator.rb +17 -10
  10. data/datamapper_generators/model/templates/app/models/%model_file_name%.rb +7 -5
  11. data/datamapper_generators/resource_controller/resource_controller_generator.rb +62 -27
  12. data/datamapper_generators/resource_controller/templates/app/controllers/%controller_file_name%.rb +6 -6
  13. data/datamapper_generators/resource_controller/templates/app/helpers/%controller_file_name%_helper.rb +1 -1
  14. data/datamapper_generators/resource_controller/templates/app/views/%controller_file_name%/edit.html.erb +19 -1
  15. data/datamapper_generators/resource_controller/templates/app/views/%controller_file_name%/index.html.erb +22 -1
  16. data/datamapper_generators/resource_controller/templates/app/views/%controller_file_name%/new.html.erb +18 -1
  17. data/datamapper_generators/resource_controller/templates/app/views/%controller_file_name%/show.html.erb +12 -1
  18. data/datamapper_generators/resource_migration/USAGE +4 -0
  19. data/datamapper_generators/resource_migration/resource_migration_generator.rb +122 -0
  20. data/datamapper_generators/resource_migration/templates/class_migration.erb +13 -0
  21. data/lib/merb/orms/data_mapper/connection.rb +61 -26
  22. data/lib/merb/orms/data_mapper/database.yml.sample +32 -12
  23. data/lib/merb/orms/data_mapper/resource.rb +12 -0
  24. data/lib/merb/session/data_mapper_session.rb +47 -40
  25. data/lib/merb_datamapper.rb +15 -11
  26. data/lib/merb_datamapper/merbtasks.rb +42 -13
  27. data/lib/merb_datamapper/version.rb +5 -0
  28. data/spec/connection_spec.rb +67 -0
  29. data/spec/spec.opts +2 -0
  30. data/spec/spec_helper.rb +15 -0
  31. metadata +58 -45
  32. data/README +0 -10
  33. data/lib/merb/orms/data_mapper/base.rb +0 -6
  34. data/specs/merb_sequel_spec.rb +0 -0
  35. data/specs/spec_helper.rb +0 -2
@@ -13,4 +13,4 @@ module Merb
13
13
  <%= " " * counter %>end # <%= mod %>
14
14
  <% counter = counter - 1 -%>
15
15
  <% end -%>
16
- end
16
+ end
@@ -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,4 @@
1
+ Description:
2
+
3
+
4
+ Usage:
@@ -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
@@ -0,0 +1,13 @@
1
+ migration(<%= number %>, :<%= migration_name %>) do
2
+ up do
3
+ create_table :<%= klass_name %> do
4
+ <% properties.each do |p| %>
5
+ column <%= p -%>
6
+ <% end %>
7
+ end
8
+ end
9
+
10
+ down do
11
+ drop_table :<%= klass_name %>
12
+ end
13
+ 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.root / "config" / "database.yml" end
9
- def sample_dest() Merb.root / "config" / "database.yml.sample" end
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
- @config ||=
18
- begin
19
- # Convert string keys to symbols
20
- full_config = Erubis.load_yaml_file(config_file)
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
- Merb.logger.info!("Connecting to database...")
37
- ::DataMapper::Database.setup(config)
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
- "merb/session/data_mapper_session",
51
- "Using DataMapper database sessions")
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
- :development: &defaults
4
- :adapter: postgresql
5
- :database: sample_development
6
- :username: the_user
7
- :password: secrets
8
- :host: localhost
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
- :test:
11
- <<: *defaults
12
- :database: sample_test
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
- :production:
15
- <<: *defaults
16
- :database: sample_production
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
@@ -0,0 +1,12 @@
1
+ module Merb
2
+ module Orms
3
+ module DataMapper
4
+ module Resource
5
+ def to_param
6
+ key
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
12
+ DataMapper::Resource.send(:include, Merb::Orms::DataMapper::Resource)
@@ -1,4 +1,10 @@
1
- require 'data_mapper'
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 < DataMapper::Base
25
-
26
- set_table_name "sessions"
27
- property :session_id, :string, :length => 255, :lazy => false, :key => true
28
- property :data, :text, :lazy => false
29
- property :updated_at, :datetime
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
- create(:session_id => Merb::SessionMixin::rand_uuid, :data =>{})
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[session_id]
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 || @unmarshalled_data = self.class.unmarshal(@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
- before_save :serialize_data
100
-
112
+
113
+ before :save, :serialize_data
114
+
101
115
  def serialize_data
102
- @data = self.class.marshal(self.data)
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