crhym3-imexport 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. data/CHANGELOG +9 -2
  2. data/README.rdoc +18 -5
  3. data/Rakefile +5 -1
  4. data/imexport.gemspec +2 -2
  5. data/lib/imexport.rb +132 -94
  6. metadata +2 -2
data/CHANGELOG CHANGED
@@ -1,3 +1,10 @@
1
- == 0.1.2
2
- * Adding support for models within a namespace (using eval() now).
1
+ v0.1.3 (Aprile 29th, 2009)
2
+
3
+ * Bugfixing (wasn't saving the last record).
4
+ * Adding :verbose option (see README.rdoc).
5
+ * ImExport::import() is now oboslete. Use ImExport::Import.from_file().
6
+
7
+ v0.1.2
8
+
9
+ * Adding support for models within a namespace (using eval() now with a regexp).
3
10
 
data/README.rdoc CHANGED
@@ -153,11 +153,12 @@ So, the complete rake task would look like this:
153
153
  Also, you can pass a block to ImExport::import. In that case you'll have to
154
154
  call model.save or model.update_attributes(...) yourself:
155
155
 
156
- ImExport::import(ENV['FROM_FILE'], {
157
- :class_name => 'Seminar',
158
- :find_by => 'title',
159
- :db_columns_prefix => 'COLUMN_',
160
- :map => COLUMNS_TO_MODEL_MAP}) do |seminar|
156
+ ImExport::Import.from_file(ENV['FROM_FILE'], {
157
+ :class_name => 'Seminar',
158
+ :find_by => 'title',
159
+ :db_columns_prefix => 'COLUMN_',
160
+ :verbose => false,
161
+ :map => COLUMNS_TO_MODEL_MAP}) do |seminar|
161
162
 
162
163
  # do something with seminar object here, e.g.
163
164
  # seminar.save
@@ -182,6 +183,14 @@ call model.save or model.update_attributes(...) yourself:
182
183
  Column name prefix that should be skipped while looking for the corresponding
183
184
  model attribute name. Againg, considering previous example, +COLUMN_title+
184
185
  actually means +title+ attribute of +Seminar+ model.
186
+
187
+ +verbose+::
188
+ +true+, +false+ or +Proc+.new { |model| }.
189
+ In cases where model.valid? returns false ImExport might output an error
190
+ (WARNING) message. +Verbose+ option tells it whether do it or not. In case
191
+ +verbose+ is a Proc, the latter being passed the model in question and should
192
+ return +true+ or +false+.
193
+ Default is +true+.
185
194
 
186
195
  +map+::
187
196
  Hash.
@@ -211,6 +220,10 @@ call model.save or model.update_attributes(...) yourself:
211
220
 
212
221
  sudo gem install crhym3-imexport
213
222
 
223
+ If that fails execute the following and try it again.
224
+
225
+ gem sources -a http://gems.github.com/
226
+
214
227
  == License
215
228
 
216
229
  Copyright (c) 2009 Alex Vagin, released under the MIT license.
data/Rakefile CHANGED
@@ -2,13 +2,17 @@ require 'rubygems'
2
2
  require 'rake'
3
3
  require 'echoe'
4
4
 
5
- Echoe.new('imexport', '0.1.2') do |p|
5
+ Echoe.new('imexport', '0.1.3') do |p|
6
6
  p.description = "Simple import from a text file generated by mysql -E ..."
7
7
  p.url = "http://github.com/crhym3/imexport"
8
8
  p.author = "alex"
9
9
  p.email = "alex@digns.com"
10
10
  p.ignore_pattern = ["tmp/*", "script/*"]
11
11
  p.development_dependencies = []
12
+
13
+ # github can't sign gems, yet
14
+ p.certificate_chain = nil
15
+ p.private_key = nil
12
16
  end
13
17
 
14
18
  Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
data/imexport.gemspec CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{imexport}
5
- s.version = "0.1.2"
5
+ s.version = "0.1.3"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["alex"]
9
- s.date = %q{2009-04-28}
9
+ s.date = %q{2009-04-29}
10
10
  s.description = %q{Simple import from a text file generated by mysql -E ...}
11
11
  s.email = %q{alex@digns.com}
12
12
  s.extra_rdoc_files = ["CHANGELOG", "TODO", "lib/imexport.rb", "README.rdoc"]
data/lib/imexport.rb CHANGED
@@ -1,107 +1,145 @@
1
1
  module ImExport
2
- def self.import(file_name, options = {})
3
- if options[:class_name] =~ /[^a-zA-Z\:]+/
4
- raise "#{options[:class_name]} doesn't look like a class name"
5
- end
6
-
7
- ## e.g. :seminar => "seminar" => "Seminar" => Seminar
8
- model = eval(options[:class_name].to_s.classify)
9
-
10
- ## used to check for an existing record. so we do update_attributes()
11
- # instead of save() in that case
12
- find_method = "find_by_#{options[:find_by]}"
13
-
14
- ## helps to distinguish between real columns and column content
15
- # could be something like "COLUMN_"
16
- columns_prefix = options[:db_columns_prefix].to_s
17
-
18
- ## for each line, this is how we check for a new column or cont.
19
- # from the previous line
20
- scan_regexp = Regexp.new("^\\s*#{columns_prefix}(\\w+)\\: (.*)")
21
-
22
- ## table columns --> model attributes mapping
23
- # if an attribute is not specified and present as a column,
24
- # it'll try figure it out:
25
- # { 'title' => :title } - works w/o expicit mapping
26
- attr_map = options[:map] || {}
27
-
28
- ## Read the file
29
- # we assume it's been created with vertial columns layout (mysql -E ...)
30
- IO.foreach(file_name) do |line|
31
- ## mysql -E ... does this:
32
- # ********* 1. row **********
33
- # column: value
34
- # another_column: value
35
- # ********* 2. row **********
36
- unless (line =~ /^\*+ \d+\. row \*+$/).nil?
37
- ## We've got a new row
38
- unless block_given?
39
- ## Save previously created object ...
40
- if !@model.nil? and @model.valid?
41
- if (s = model.send("#{find_method}", @model.title))
42
- s.update_attributes(@model.attributes.reject{|k,v| v.nil?})
43
- else
44
- @model.save
45
- end
46
- else
47
- $stderr.puts "\n>>> ERRORS while storing #{options[:class_name]}: #{@model.errors.full_messages.join('; ')}\n#{@model.inspect}" unless @model.nil?
48
- end
49
- else
50
- ## or pass it to a block
51
- # in this case we don't do any validations
52
- yield(@model)
53
- end
54
-
55
- # ... then create a new one
56
- #$stderr.puts "\n###################################"
57
- @model = model.new
58
- @last_column_name = nil
59
- @last_column_content = nil
60
- next
2
+ def self.import(file_name, options)
3
+ puts "WARNING: ImExport::import() method is obsolete.\nYou should use ImExport::Import.from_file() instead.\n"
4
+ Import.from_file file_name, options
5
+ end
6
+
7
+ class Import
8
+ def self.from_file(file_name, options = {})
9
+ if options[:class_name] =~ /[^a-zA-Z\:]+/
10
+ raise "#{options[:class_name]} doesn't look like a class name"
61
11
  end
62
12
 
63
- ## Cont. of the same row.
64
- ## It's one table column at a time (or more lines).
65
- ## Parse it and add set the corresponding attribute in the model
66
- line.chomp!
67
- column = line.scan(scan_regexp)
68
- #$stderr.puts column.inspect
13
+ ## e.g. :seminar => "seminar" => "Seminar" => Seminar
14
+ model = eval(options[:class_name].to_s.classify)
69
15
 
70
- unless column.size > 0
71
- ## this is a column continuation of the previous line
72
- @last_column_content << '<br/>' << line
73
- next
74
- end
16
+ ## used to check for an existing record. so we do update_attributes()
17
+ # instead of save() in that case
18
+ #
19
+ # Example:
20
+ # :find_by => :title # model.find_by_title
21
+ @@find_by_attribute = options[:find_by].to_s
22
+
23
+ ## helps to distinguish between real columns and column content
24
+ # could be something like "COLUMN_"
25
+ columns_prefix = options[:db_columns_prefix].to_s
26
+
27
+ ## for each line, this is how we check for a new column or cont.
28
+ # from the previous line
29
+ scan_regexp = Regexp.new("^\\s*#{columns_prefix}(\\w+)\\: (.*)")
75
30
 
76
- ## this is a new model attribute
77
- # set last attribute in the model if defined
78
- # we should have at least two items in the array
79
- column.flatten!
80
- @last_column_name = column.first
81
- @last_column_content = column[1].gsub(/\t+/, " ").strip.gsub(/^\n+$/, "").gsub(/\n+/, "<br/>")
31
+ ## table columns --> model attributes mapping
32
+ # if an attribute is not specified and present as a column,
33
+ # it'll try figure it out:
34
+ # { 'title' => :title } - works w/o expicit mapping
35
+ attr_map = options[:map] || {}
82
36
 
83
- # in column-to-model map
84
- if attr_map.include?(@last_column_name)
85
- mattr = attr_map[@last_column_name]
86
- case
87
- when mattr.kind_of?(Symbol)
88
- @model.send("#{mattr.to_s}=", @last_column_content)
89
- when mattr.kind_of?(Proc)
90
- mattr.call(@last_column_content, @model)
91
- when mattr.kind_of?(Hash)
92
- @model.send("#{mattr.keys.first}=", mattr.values.first.call(@last_column_content))
37
+ ## verbose option
38
+ # is a Proc type. Should return true or false.
39
+ # If true a warning message outputs to stderr in case !model.valid?
40
+ #
41
+ # Example:
42
+ # verbose => Proc.new { |seminar| seminar.date.future? }
43
+ #
44
+ # verbose => nil or not specifying this options at all makes it silent
45
+ @@verbose = options.include?(:verbose) ? options[:verbose] : true # default is verbose
46
+
47
+ ## Read the file
48
+ # we assume it's been created with vertial columns layout (mysql -E ...)
49
+ model_inst = nil
50
+ IO.foreach(file_name) do |line|
51
+ ## mysql -E ... does this:
52
+ # ********* 1. row **********
53
+ # column: value
54
+ # another_column: value
55
+ # ...
56
+ # ********* 2. row **********
57
+ unless (line =~ /^\*+ \d+\. row \*+$/).nil?
58
+ ## We've got a new row
59
+ # save or update previously created object ...
60
+ unless block_given?
61
+ save_or_update(model_inst) if model_inst
93
62
  else
94
- $stderr.puts "WARNING: don't know how to handle #{mattr.inspect}"
63
+ ## or pass it to a block
64
+ # in this case we don't do any validations
65
+ yield(model_inst)
66
+ end
67
+
68
+ # ... then create a new one
69
+ #$stderr.puts "\n###################################"
70
+ model_inst = model.new
71
+ @last_column_name = nil
72
+ @last_column_content = nil
73
+ next
74
+ end
75
+
76
+ ## Cont. of the same row.
77
+ ## It's one table column at a time (or more lines).
78
+ ## Parse it and add set the corresponding attribute in the model
79
+ line.chomp!
80
+ column = line.scan(scan_regexp)
81
+ #$stderr.puts column.inspect
82
+
83
+ unless column.size > 0
84
+ ## this is a column continuation of the previous line
85
+ @last_column_content << '<br/>' << line
86
+ next
95
87
  end
96
88
 
97
- # simple auto-mapping
98
- elsif @model.respond_to?(@last_column_name.to_sym)
99
- @model.send("#{@last_column_name}=", @last_column_content)
89
+ ## this is a new model attribute
90
+ # set last attribute in the model if defined
91
+ # we should have at least two items in the array
92
+ column.flatten!
93
+ @last_column_name = column.first
94
+ @last_column_content = column[1].gsub(/\t+/, " ").strip.gsub(/^\n+$/, "").gsub(/\n+/, "<br/>")
100
95
 
101
- # otherwise we don't know how to do it
96
+ # in column-to-model map
97
+ if attr_map.include?(@last_column_name)
98
+ mattr = attr_map[@last_column_name]
99
+ case
100
+ when mattr.kind_of?(Symbol)
101
+ model_inst.send("#{mattr.to_s}=", @last_column_content)
102
+ when mattr.kind_of?(Proc)
103
+ mattr.call(@last_column_content, model_inst)
104
+ when mattr.kind_of?(Hash)
105
+ model_inst.send("#{mattr.keys.first}=", mattr.values.first.call(@last_column_content))
106
+ else
107
+ $stderr.puts "WARNING: don't know how to handle #{mattr.inspect}"
108
+ end
109
+
110
+ # simple auto-mapping
111
+ elsif model_inst.respond_to?("#{@last_column_name}=")
112
+ model_inst.send("#{@last_column_name}=", @last_column_content)
113
+
114
+ # otherwise we don't know how to do it
115
+ else
116
+ $stderr.puts "WARNING: don't know how to set :#{@last_column_name}"
117
+ end
118
+ end # IO.foreach
119
+
120
+ # TODO: more DRY
121
+ # save the last one
122
+ unless block_given?
123
+ save_or_update(model_inst) if model_inst
102
124
  else
103
- $stderr.puts "WARNING: don't know how to set :#{@last_column_name}"
125
+ ## or pass it to a block
126
+ # in this case we don't do any validations
127
+ yield(model_inst)
104
128
  end
105
- end # IO.foreach
106
- end
129
+ end
130
+
131
+ def self.save_or_update(model)
132
+ # save it if valid or say an error
133
+ if !model.nil? and model.valid?
134
+ if (s = model.class.send("find_by_#{@@find_by_attribute}", model.read_attribute(@@find_by_attribute)))
135
+ s.update_attributes(model.attributes.reject{|k,v| v.nil?})
136
+ else
137
+ model.save
138
+ end
139
+ elsif (@@verbose.kind_of?(Proc) ? @@verbose.call(model) : @@verbose)
140
+ $stderr.puts "\n>>> ERRORS while storing #{model.class.to_s}: #{model.errors.full_messages.join('; ')}\n#{model.inspect}" unless model.nil?
141
+ end
142
+ end
143
+ end # class Import
144
+
107
145
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: crhym3-imexport
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - alex
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-04-28 00:00:00 -07:00
12
+ date: 2009-04-29 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15