jinx-migrate 2.1.1 → 2.1.2

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