merb_datamapper 0.9.2 → 0.9.3

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.
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