crhym3-imexport 0.1.2 → 0.1.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 (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