jinx-migrate 2.1.1 → 2.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -3,6 +3,6 @@ gemspec
3
3
 
4
4
  group :development do
5
5
  # Uncomment to use the local development project.
6
- gem 'jinx', :path => File.dirname(__FILE__) + '/../core'
6
+ #gem 'jinx', :path => File.dirname(__FILE__) + '/../core'
7
7
  gem 'jinx-migrate', :path => File.dirname(__FILE__)
8
8
  end
data/History.md CHANGED
@@ -1,6 +1,10 @@
1
1
  This history lists major release themes. See the GitHub commits (https://github.com/jinx/migrate)
2
2
  for change details.
3
3
 
4
+ 2.1.2 / 2012-06-12
5
+ ------------------
6
+ * Support caSmall web service.
7
+
4
8
  2.1.1 / 2012-04-13
5
9
  ------------------
6
10
  * Initial public release spun off from caruby/core.
@@ -110,7 +110,7 @@ module Jinx
110
110
  when Enumerable then
111
111
  ''.parse_csv(:headers => hdr_opt, :header_converters => :symbol, :return_headers => true)
112
112
  else
113
- Jinx.fail(ArgumentError, "CSV headers option value not supported: #{hdr_opt}")
113
+ raise ArgumentError.new("CSV headers option value not supported: #{hdr_opt}")
114
114
  end
115
115
  # The field value accessors consist of the header row headers converted to a symbol.
116
116
  @accessors = hdr_row.headers
@@ -139,7 +139,7 @@ module Jinx
139
139
  reopt = if opt then
140
140
  case opt
141
141
  when 'i' then Regexp::IGNORECASE
142
- else Jinx.fail(MigrationError, "Migration value filter regular expression #{k} qualifier not supported: expected 'i', found '#{opt}'")
142
+ else raise MigrationError.new("Migration value filter regular expression #{k} qualifier not supported: expected 'i', found '#{opt}'")
143
143
  end
144
144
  end
145
145
  # the Regexp object
@@ -7,7 +7,6 @@ require 'jinx/helpers/lazy_hash'
7
7
  require 'jinx/helpers/log'
8
8
  require 'jinx/helpers/inflector'
9
9
  require 'jinx/helpers/pretty_print'
10
- require 'jinx/helpers/stopwatch'
11
10
  require 'jinx/helpers/transitive_closure'
12
11
  require 'jinx/migration/migratable'
13
12
  require 'jinx/migration/reader'
@@ -20,15 +19,13 @@ module Jinx
20
19
  class Migrator
21
20
  include Enumerable
22
21
 
23
- # Creates a new Migrator. The input can be either a file name or a source factory. The factory
24
- # implements the +open+ method, which returns a {Migration::Reader}
22
+ # Creates a new Migrator from the given options.
25
23
  #
26
24
  # @param [{Symbol => Object}] opts the migration options
27
- # @option opts [String] :target the required target domain class
25
+ # @option opts [Class] :target the required target domain class
28
26
  # @option opts [<String>, String] :mapping the required input field => caTissue attribute mapping file(s)
29
27
  # @option opts [String, Migration::Reader] :input the required input file name or an adapter which
30
28
  # implements the {Migration::Reader} methods
31
- # @option opts [Jinx::Database] :database the optional destination +Jinx::Database+
32
29
  # @option opts [<String>, String] :defaults the optional caTissue attribute => value default mapping file(s)
33
30
  # @option opts [<String>, String] :filters the optional caTissue attribute input value => caTissue value filter file(s)
34
31
  # @option opts [<String>, String] :shims the optional shim file(s) to load
@@ -48,30 +45,13 @@ module Jinx
48
45
  parse_options(opts)
49
46
  build
50
47
  end
51
-
52
- # Imports this migrator's file into the database with the given connect options.
53
- # This method creates or updates the domain objects mapped from the import source.
54
- # If a block is given to this method, then the block is called on each stored
55
- # migration target object.
56
- #
57
- # If the +:create+ option is set, then an input record for a target object which already
58
- # exists in the database is noted in a debug log message and ignored rather than updated.
59
- #
60
- # @yield (see #migrate)
61
- # @yieldparam (see #migrate)
62
- # @return (see #migrate)
63
- def migrate_to_database(&block)
64
- # migrate with save
65
- tm = Stopwatch.measure { execute_save(&block) }.elapsed
66
- logger.debug { format_migration_time_log_message(tm) }
67
- end
68
48
 
69
49
  # Imports this migrator's CSV file and calls the given block on each migrated target
70
50
  # domain object. If no block is given, then this method returns an array of the
71
51
  # migrated target objects.
72
52
  #
73
- # @yield [target, row] operation performed on the migration target
74
- # @yieldparam [Jinx::Resource] target the migrated target domain object
53
+ # @yield [target, row] operates on the migration target
54
+ # @yieldparam [Resource] target the migrated target domain object
75
55
  # @yieldparam [{Symbol => Object}] row the migration source record
76
56
  def migrate(&block)
77
57
  unless block_given? then
@@ -150,46 +130,10 @@ module Jinx
150
130
  end
151
131
  end
152
132
 
153
- # {#migrate} with a {#save} block on the migration target. Each migrated object
154
- # is created, if necessary, after the target save.
155
- def execute_save
156
- if @database.nil? then
157
- Jinx.fail(MigrationError, "Migrator cannot save records since the database option was not specified.")
158
- end
159
- @database.open do |db|
160
- migrate do |tgt, rec|
161
- save(tgt, db)
162
- # Ensure that each migrated object is created if necessary.
163
- @migrated.each do |obj|
164
- next if obj.identifier
165
- logger.debug { "The migrator is saving the migrated #{obj}..." }
166
- save(obj, db)
167
- logger.debug { "The migrator saved the migrated #{obj}." }
168
- end
169
- yield(tgt, rec) if block_given?
170
- db.clear
171
- end
172
- end
173
- end
174
-
175
- # @return a log message String for the given migration time in seconds
176
- def format_migration_time_log_message(time)
177
- # the database execution time
178
- dt = @database.execution_time
179
- if time > 120 then
180
- time /= 60
181
- dt /= 60
182
- unit = "minutes"
183
- else
184
- unit = "seconds"
185
- end
186
- "Migration took #{'%.2f' % time} #{unit}, of which #{'%.2f' % dt} were database operations."
187
- end
188
-
189
133
  def parse_options(opts)
190
134
  @fld_map_files = opts[:mapping]
191
135
  if @fld_map_files.nil? then
192
- Jinx.fail(MigrationError, "Migrator missing required field mapping file parameter")
136
+ raise MigrationError.new("Migrator missing required field mapping file parameter")
193
137
  end
194
138
  @def_files = opts[:defaults]
195
139
  @flt_files = opts[:filters]
@@ -200,12 +144,11 @@ module Jinx
200
144
  @from = opts[:from] ||= 1
201
145
  @input = opts[:input]
202
146
  if @input.nil? then
203
- Jinx.fail(MigrationError, "Migrator missing required source file parameter")
147
+ raise MigrationError.new("Migrator missing required source file parameter")
204
148
  end
205
- @database = opts[:database]
206
149
  @target_class = opts[:target]
207
150
  if @target_class.nil? then
208
- Jinx.fail(MigrationError, "Migrator missing required target class parameter")
151
+ raise MigrationError.new("Migrator missing required target class parameter")
209
152
  end
210
153
  @bad_file = opts[:bad]
211
154
  @extract = opts[:extract]
@@ -225,7 +168,7 @@ module Jinx
225
168
 
226
169
  def build
227
170
  # the current source class => instance map
228
- Jinx.fail(MigrationError, "No file to migrate") if @input.nil?
171
+ raise MigrationError.new("No file to migrate") if @input.nil?
229
172
 
230
173
  # If the input is a file name, then make a CSV loader which only converts input fields
231
174
  # corresponding to non-String attributes.
@@ -258,7 +201,7 @@ module Jinx
258
201
  # An abstract class cannot be instantiated.
259
202
  @creatable_classes.each do |klass|
260
203
  if klass.abstract? then
261
- Jinx.fail(MigrationError, "Migrator cannot create the abstract class #{klass}; specify a subclass instead in the mapping file.")
204
+ raise MigrationError.new("Migrator cannot create the abstract class #{klass}; specify a subclass instead in the mapping file.")
262
205
  end
263
206
  end
264
207
 
@@ -544,7 +487,7 @@ module Jinx
544
487
  @rejects.flush
545
488
  logger.debug("Invalid record #{rec_no} was written to the rejects file #{@bad_file}.")
546
489
  else
547
- Jinx.fail(MigrationError, "Migration not performed on record #{rec_no}")
490
+ raise MigrationError.new("Migration not performed on record #{rec_no}")
548
491
  end
549
492
  # Bump the record count.
550
493
  @rec_cnt += 1
@@ -593,7 +536,7 @@ module Jinx
593
536
  # create an instance for each creatable class
594
537
  created = Set.new
595
538
  # the migrated objects
596
- migrated = @creatable_classes.map { |klass| create(klass, row, created) }
539
+ migrated = @creatable_classes.map { |klass| create_instance(klass, row, created) }
597
540
  # migrate each object from the input row
598
541
  migrated.each do |obj|
599
542
  # First uniquify the object if necessary.
@@ -691,7 +634,7 @@ module Jinx
691
634
  # @param [{Symbol => Object}] row the input row
692
635
  # @param [<Resource>] created the migrated instances for this row
693
636
  # @return [Resource] the new instance
694
- def create(klass, row, created)
637
+ def create_instance(klass, row, created)
695
638
  # the new object
696
639
  logger.debug { "The migrator is building #{klass.qp}..." }
697
640
  created << obj = klass.new
@@ -758,7 +701,7 @@ module Jinx
758
701
  # @return the new object
759
702
  def create_reference(obj, property, row, created)
760
703
  if property.type.abstract? then
761
- Jinx.fail(MigrationError, "Cannot create #{obj.qp} #{property} with abstract type #{property.type}")
704
+ raise MigrationError.new("Cannot create #{obj.qp} #{property} with abstract type #{property.type}")
762
705
  end
763
706
  ref = property.type.new
764
707
  ref.migrate(row, Array::EMPTY_ARRAY)
@@ -785,8 +728,8 @@ module Jinx
785
728
  # set the attribute
786
729
  begin
787
730
  obj.send(property.writer, value)
788
- rescue Exception => e
789
- Jinx.fail(MigrationError, "Could not set #{obj.qp} #{property} to #{value.qp}", e)
731
+ rescue Exception
732
+ raise MigrationError.new("Could not set #{obj.qp} #{property} to #{value.qp} - " + $!)
790
733
  end
791
734
  logger.debug { "Migrated #{obj.qp} #{property} to #{value}." }
792
735
  end
@@ -810,20 +753,6 @@ module Jinx
810
753
  flts = @attr_flt_hash[obj.class] || return
811
754
  flts[attribute]
812
755
  end
813
-
814
- # @param [Resource] obj the domain object to save in the database
815
- # @return [Resource, nil] obj if the save is successful, nil otherwise
816
- def save(obj, database)
817
- if @create then
818
- logger.debug { "Migrator creating #{obj}..." }
819
- database.create(obj)
820
- logger.debug { "Migrator created #{obj}." }
821
- else
822
- logger.debug { "Migrator saving #{obj}..." }
823
- database.save(obj)
824
- logger.debug { "Migrator saved #{obj}." }
825
- end
826
- end
827
756
 
828
757
  def current_record
829
758
  @rec_cnt + 1
@@ -878,7 +807,7 @@ module Jinx
878
807
  begin
879
808
  config = YAML.load_file(file)
880
809
  rescue
881
- Jinx.fail(MigrationError, "Could not read field map file #{file}: " + $!)
810
+ raise MigrationError.new("Could not read field map file #{file}: " + $!)
882
811
  end
883
812
  populate_field_map(config, hash)
884
813
  end
@@ -892,7 +821,7 @@ module Jinx
892
821
  # the header accessor method for the field
893
822
  header = @reader.accessor(field)
894
823
  if header.nil? then
895
- Jinx.fail(MigrationError, "Field defined in migration configuration not found in input file #{@input} headers: #{field}")
824
+ raise MigrationError.new("Field defined in migration configuration not found in input file #{@input} headers: #{field}")
896
825
  end
897
826
  # associate each attribute path in the property value with the header
898
827
  attr_list.split(/,\s*/).each do |path_s|
@@ -921,7 +850,7 @@ module Jinx
921
850
  begin
922
851
  config = YAML::load_file(file)
923
852
  rescue
924
- Jinx.fail(MigrationError, "Could not read defaults file #{file}: " + $!)
853
+ raise MigrationError.new("Could not read defaults file #{file}: " + $!)
925
854
  end
926
855
  # collect the class => path => value entries
927
856
  config.each do |path_s, value|
@@ -952,13 +881,15 @@ module Jinx
952
881
  begin
953
882
  config = YAML::load_file(file)
954
883
  rescue
955
- Jinx.fail(MigrationError, "Could not read filter file #{file}: " + $!)
884
+ raise MigrationError.new("Could not read filter file #{file}: " + $!)
956
885
  end
957
886
  config.each do |path_s, flt|
958
887
  next if flt.nil_or_empty?
959
888
  klass, path = create_attribute_path(path_s)
960
- unless path.size == 1 then
961
- Jinx.fail(MigrationError, "Migration filter configuration path not supported: #{path_s}")
889
+ if path.empty? then
890
+ raise MigrationError.new("Migration filter configuration path does not include a property: #{path_s}")
891
+ elsif path.size > 1 then
892
+ raise MigrationError.new("Migration filter configuration path with more than one property is not supported: #{path_s}")
962
893
  end
963
894
  pa = klass.standard_attribute(path.first.to_sym)
964
895
  flt_hash = hash[klass] ||= {}
@@ -973,10 +904,10 @@ module Jinx
973
904
  names = path_s.split('.')
974
905
  # If the path starts with a capitalized class name, then resolve the class.
975
906
  # Otherwise, the target class is the start of the path.
976
- klass = names.first =~ /^[A-Z]/ ? context_module.module_for_name(names.shift) : @target_class
907
+ klass = names.first =~ /^[A-Z]/ ? class_for_name(names.shift) : @target_class
977
908
  # There must be at least one attribute.
978
909
  if names.empty? then
979
- Jinx.fail(MigrationError, "Property entry in migration configuration is not in <class>.<attribute> format: #{path_s}")
910
+ raise MigrationError.new("Property entry in migration configuration is not in <class>.<attribute> format: #{path_s}")
980
911
  end
981
912
 
982
913
  # Build the attribute path.
@@ -985,11 +916,11 @@ module Jinx
985
916
  pa = name.to_sym
986
917
  prop = begin
987
918
  parent.property(pa)
988
- rescue NameError => e
989
- Jinx.fail(MigrationError, "Migration field mapping attribute #{parent.qp}.#{pa} not found", e)
919
+ rescue NameError
920
+ raise MigrationError.new("Migration field mapping attribute #{parent}.#{pa} not found - " + $!)
990
921
  end
991
922
  if prop.collection? then
992
- Jinx.fail(MigrationError, "Migration field mapping attribute #{parent.qp}.#{prop} is a collection, which is not supported")
923
+ raise MigrationError.new("Migration field mapping attribute #{parent}.#{prop} is a collection, which is not supported")
993
924
  end
994
925
  path << prop
995
926
  prop.type
@@ -1008,6 +939,13 @@ module Jinx
1008
939
  def context_module
1009
940
  @target_class.domain_module
1010
941
  end
942
+
943
+ # @param [String] the class name to resolve in the context of this migrator
944
+ # @return [Class] the corresponding class
945
+ # @raise [NameError] if the name cannot be resolved
946
+ def class_for_name(name)
947
+ context_module.module_for_name(name)
948
+ end
1011
949
 
1012
950
  # @return a new class => [paths] hash from the migration fields configuration map
1013
951
  def create_class_paths_hash(fld_map, def_map)
@@ -1,5 +1,5 @@
1
1
  module Jinx
2
2
  module Migrate
3
- VERSION = "2.1.1"
3
+ VERSION = '2.1.2'
4
4
  end
5
5
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: jinx-migrate
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 2.1.1
5
+ version: 2.1.2
6
6
  platform: ruby
7
7
  authors:
8
8
  - OHSU
@@ -10,8 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2012-04-13 00:00:00 -07:00
14
- default_executable:
13
+ date: 2012-06-12 00:00:00 Z
15
14
  dependencies:
16
15
  - !ruby/object:Gem::Dependency
17
16
  name: rack
@@ -81,7 +80,6 @@ files:
81
80
  - .rspec
82
81
  - .yardopts
83
82
  - Gemfile
84
- - Gemfile.lock
85
83
  - History.md
86
84
  - LEGAL
87
85
  - LICENSE
@@ -141,7 +139,6 @@ files:
141
139
  - test/fixtures/csv/data/empty.csv
142
140
  - test/fixtures/csv/data/variety.csv
143
141
  - test/lib/csv/csvio_test.rb
144
- has_rdoc: yard
145
142
  homepage: http://github.com/jinx/migrate
146
143
  licenses:
147
144
  - MIT
@@ -165,7 +162,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
165
162
  requirements: []
166
163
 
167
164
  rubyforge_project: jinx
168
- rubygems_version: 1.5.1
165
+ rubygems_version: 1.8.15
169
166
  signing_key:
170
167
  specification_version: 3
171
168
  summary: Jinx JSON plug-in.
@@ -204,3 +201,4 @@ test_files:
204
201
  - spec/unique/parents.csv
205
202
  - spec/unique/shims.rb
206
203
  - spec/unique/unique_spec.rb
204
+ has_rdoc: yard
@@ -1,38 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- jinx-migrate (2.1.1)
5
- bundler
6
- fastercsv
7
- rack
8
-
9
- PATH
10
- remote: /Users/loneyf/workspace/jinx/core
11
- specs:
12
- jinx (2.1.1)
13
- bundler
14
-
15
- GEM
16
- remote: http://rubygems.org/
17
- specs:
18
- diff-lcs (1.1.3)
19
- fastercsv (1.5.4)
20
- rack (1.4.1)
21
- rake (0.9.2.2)
22
- rspec (2.9.0)
23
- rspec-core (~> 2.9.0)
24
- rspec-expectations (~> 2.9.0)
25
- rspec-mocks (~> 2.9.0)
26
- rspec-core (2.9.0)
27
- rspec-expectations (2.9.1)
28
- diff-lcs (~> 1.1.3)
29
- rspec-mocks (2.9.0)
30
-
31
- PLATFORMS
32
- java
33
-
34
- DEPENDENCIES
35
- jinx!
36
- jinx-migrate!
37
- rake
38
- rspec (>= 2.6)