enhanced_marc 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/Changes +1 -0
  2. data/LICENSE +21 -0
  3. data/README +51 -0
  4. data/Rakefile +41 -0
  5. data/VERSION +1 -0
  6. data/enhanced_marc-0.1.gem +0 -0
  7. data/enhanced_marc.gemspec +85 -0
  8. data/lib/enhanced_marc.rb +23 -0
  9. data/lib/enhanced_marc/book_record.rb +37 -0
  10. data/lib/enhanced_marc/book_type.rb +87 -0
  11. data/lib/enhanced_marc/computer_record.rb +37 -0
  12. data/lib/enhanced_marc/computer_type.rb +14 -0
  13. data/lib/enhanced_marc/leader.rb +132 -0
  14. data/lib/enhanced_marc/leftovers.rb +122 -0
  15. data/lib/enhanced_marc/map_record.rb +38 -0
  16. data/lib/enhanced_marc/map_type.rb +99 -0
  17. data/lib/enhanced_marc/mixed_record.rb +37 -0
  18. data/lib/enhanced_marc/mixed_type.rb +4 -0
  19. data/lib/enhanced_marc/reader.rb +105 -0
  20. data/lib/enhanced_marc/record.rb +96 -0
  21. data/lib/enhanced_marc/record_type.rb +310 -0
  22. data/lib/enhanced_marc/score_record.rb +38 -0
  23. data/lib/enhanced_marc/score_type.rb +4 -0
  24. data/lib/enhanced_marc/serial_record.rb +37 -0
  25. data/lib/enhanced_marc/serial_type.rb +87 -0
  26. data/lib/enhanced_marc/sound_record.rb +37 -0
  27. data/lib/enhanced_marc/sound_type.rb +4 -0
  28. data/lib/enhanced_marc/visual_record.rb +37 -0
  29. data/lib/enhanced_marc/visual_type.rb +38 -0
  30. data/lib/enhanced_marc/xmlreader.rb +58 -0
  31. data/pkg/enhanced_marc-0.1.gem +0 -0
  32. data/pkg/enhanced_marc-0.1.tgz +0 -0
  33. data/pkg/enhanced_marc-0.1.zip +0 -0
  34. data/pkg/enhanced_marc-0.1/Changes +1 -0
  35. data/pkg/enhanced_marc-0.1/LICENSE +21 -0
  36. data/pkg/enhanced_marc-0.1/README +51 -0
  37. data/pkg/enhanced_marc-0.1/Rakefile +41 -0
  38. data/pkg/enhanced_marc-0.1/test/ts_enhanced_marc.rb +5 -0
  39. data/test/ts_enhanced_marc.rb +5 -0
  40. metadata +113 -0
@@ -0,0 +1,122 @@
1
+ def get_fixed_field_position
2
+ ff_pos = {
3
+ 'Ctry' => {
4
+ '008' => {
5
+ 'BKS' => {:start => 15, :len => 3, :def => ' ' },
6
+ 'SER' => {:start => 15, :len => 3, :def => ' ' },
7
+ 'VIS' => {:start => 15, :len => 3, :def => ' ' },
8
+ 'MIX' => {:start => 15, :len => 3, :def => ' ' },
9
+ 'MAP' => {:start => 15, :len => 3, :def => ' ' },
10
+ 'SCO' => {:start => 15, :len => 3, :def => ' ' },
11
+ 'REC' => {:start => 15, :len => 3, :def => ' ' },
12
+ 'COM' => {:start => 15, :len => 3, :def => ' ' }
13
+ }
14
+ },
15
+ 'Lang' => {
16
+ '008' => {
17
+ 'BKS' => {:start => 35, :len => 3, :def => ' ' },
18
+ 'SER' => {:start => 35, :len => 3, :def => ' ' },
19
+ 'VIS' => {:start => 35, :len => 3, :def => ' ' },
20
+ 'MIX' => {:start => 35, :len => 3, :def => ' ' },
21
+ 'MAP' => {:start => 35, :len => 3, :def => ' ' },
22
+ 'SCO' => {:start => 35, :len => 3, :def => ' ' },
23
+ 'REC' => {:start => 35, :len => 3, :def => ' ' },
24
+ 'COM' => {:start => 35, :len => 3, :def => ' ' }
25
+ }
26
+ },
27
+ 'MRec' => {
28
+ '008' => {
29
+ 'BKS' => {:start => 38, :len => 3, :def => ' ' },
30
+ 'SER' => {:start => 38, :len => 3, :def => ' ' },
31
+ 'VIS' => {:start => 38, :len => 3, :def => ' ' },
32
+ 'MIX' => {:start => 38, :len => 3, :def => ' ' },
33
+ 'MAP' => {:start => 38, :len => 3, :def => ' ' },
34
+ 'SCO' => {:start => 38, :len => 3, :def => ' ' },
35
+ 'REC' => {:start => 38, :len => 3, :def => ' ' },
36
+ 'COM' => {:start => 38, :len => 3, :def => ' ' }
37
+ }
38
+ },
39
+ 'DtSt' => {
40
+ '008' => {
41
+ 'BKS' => {:start => 6, :len => 1, :def => ' ' },
42
+ 'SER' => {:start => 6, :len => 1, :def => 'c' },
43
+ 'VIS' => {:start => 6, :len => 1, :def => ' ' },
44
+ 'MIX' => {:start => 6, :len => 1, :def => ' ' },
45
+ 'MAP' => {:start => 6, :len => 1, :def => ' ' },
46
+ 'SCO' => {:start => 6, :len => 1, :def => ' ' },
47
+ 'REC' => {:start => 6, :len => 1, :def => ' ' },
48
+ 'COM' => {:start => 6, :len => 1, :def => ' ' },
49
+ }
50
+ },
51
+ 'Type' => {
52
+ 'ldr' => {
53
+ 'BKS' => {:start => 6, :len => 1, :def => 'a' },
54
+ 'SER' => {:start => 6, :len => 1, :def => 'a' },
55
+ 'VIS' => {:start => 6, :len => 1, :def => 'g' },
56
+ 'MIX' => {:start => 6, :len => 1, :def => 'p' },
57
+ 'MAP' => {:start => 6, :len => 1, :def => 'e' },
58
+ 'SCO' => {:start => 6, :len => 1, :def => 'c' },
59
+ 'REC' => {:start => 6, :len => 1, :def => 'i' },
60
+ 'COM' => {:start => 6, :len => 1, :def => 'm' },
61
+ }
62
+ },
63
+ 'Ctrl' => {
64
+ 'ldr' => {
65
+ 'BKS' => {:start => 8, :len => 1, :def => ' ' },
66
+ 'SER' => {:start => 8, :len => 1, :def => ' ' },
67
+ 'VIS' => {:start => 8, :len => 1, :def => ' ' },
68
+ 'MIX' => {:start => 8, :len => 1, :def => ' ' },
69
+ 'MAP' => {:start => 8, :len => 1, :def => ' ' },
70
+ 'SCO' => {:start => 8, :len => 1, :def => ' ' },
71
+ 'REC' => {:start => 8, :len => 1, :def => ' ' },
72
+ 'COM' => {:start => 8, :len => 1, :def => ' ' },
73
+ }
74
+ },
75
+ 'BLvl' => {
76
+ 'ldr'=> {
77
+ 'BKS' => {:start => 7, :len => 1, :def => 'm' },
78
+ 'SER' => {:start => 7, :len => 1, :def => 's' },
79
+ 'VIS' => {:start => 7, :len => 1, :def => 'm' },
80
+ 'MIX' => {:start => 7, :len => 1, :def => 'c' },
81
+ 'MAP' => {:start => 7, :len => 1, :def => 'm' },
82
+ 'SCO' => {:start => 7, :len => 1, :def => 'm' },
83
+ 'REC' => {:start => 7, :len => 1, :def => 'm' },
84
+ 'COM' => {:start => 7, :len => 1, :def => 'm' },
85
+ }
86
+ },
87
+ 'Desc' => {
88
+ 'ldr' => {
89
+ 'BKS' => {:start => 18, :len => 1, :def => ' ' },
90
+ 'SER' => {:start => 18, :len => 1, :def => ' ' },
91
+ 'VIS' => {:start => 18, :len => 1, :def => ' ' },
92
+ 'MIX' => {:start => 18, :len => 1, :def => ' ' },
93
+ 'MAP' => {:start => 18, :len => 1, :def => ' ' },
94
+ 'SCO' => {:start => 18, :len => 1, :def => ' ' },
95
+ 'REC' => {:start => 18, :len => 1, :def => ' ' },
96
+ 'COM' => {:start => 18, :len => 1, :def => ' ' },
97
+ }
98
+ },
99
+ 'ELvl' => {
100
+ 'ldr' => {
101
+ 'BKS' => {:start => 17, :len => 1, :def => ' ' },
102
+ 'SER' => {:start => 17, :len => 1, :def => ' ' },
103
+ 'VIS' => {:start => 17, :len => 1, :def => ' ' },
104
+ 'MIX' => {:start => 17, :len => 1, :def => ' ' },
105
+ 'MAP' => {:start => 17, :len => 1, :def => ' ' },
106
+ 'SCO' => {:start => 17, :len => 1, :def => ' ' },
107
+ 'REC' => {:start => 17, :len => 1, :def => ' ' },
108
+ 'COM' => {:start => 17, :len => 1, :def => ' ' },
109
+ }
110
+ },
111
+ 'TMat' => {
112
+ '008' => {
113
+ 'VIS' => {:start => 33, :len => 1, :def => ' ' },
114
+ },
115
+ '006' => {
116
+ 'VIS' => {:start => 16, :len => 1, :def => ' ' },
117
+ }
118
+ },
119
+ }
120
+
121
+
122
+ end
@@ -0,0 +1,38 @@
1
+ module MARC
2
+
3
+ # A class that represents an individual MARC record. Every record
4
+ # is made up of a collection of MARC::Field objects.
5
+
6
+ class MapRecord < Record
7
+
8
+ def initialize
9
+ super
10
+ @leader[6] = 'e' if @leader[6,1] == ' '
11
+ @leader[7] = 'm' if @leader[7,1] == ' '
12
+ @record_type = 'MAP'
13
+ @bibliographic_level = @leader.get_blvl
14
+ self.extend MapType
15
+ self.inspect_fixed_fields
16
+ end
17
+
18
+ def is_valid_type?
19
+ return false unless @leader[6,1].match(/[ef]{1}/)
20
+ return true
21
+ end
22
+ def is_valid_blvl?
23
+ return true if @leader[7,1].match(/[acdim]{1}/) and @leader[6,1].match('f')
24
+ return true if @leader[7,1].match(/[abcdims]{1}/) and @leader[6,1].match('e')
25
+ return false
26
+ end
27
+ def self.new_from_record(record)
28
+ rec = MapRecord.new
29
+ record.instance_variables.each { | var |
30
+ rec.instance_variable_set(var, record.instance_variable_get(var))
31
+ }
32
+ return Exception.new("Incorrect type declaration in leader") unless rec.is_valid_type?
33
+ return Exception.new("Incorrect bibliographic declaration in leader") unless rec.is_valid_blvl?
34
+ return rec
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,99 @@
1
+ module MapType
2
+ include RecordType
3
+ public :is_govdoc?, :form, :has_index?
4
+ def cartographic_type(human_readable=false)
5
+ crtp_map = {'a'=>'Map', 'b'=>'Map series', 'c'=>'Map serial', 'd'=>'Globe', 'e'=>'Atlas',
6
+ 'f'=>'Supplement', 'g'=>'Bound as part of another work', 'u'=>'Unknown', 'z'=>'Other'}
7
+ human_readable = crtp_map if human_readable
8
+ return self.field_parser({:match=>'MAP', :start=>25,:end=>1}, {:match=>/[ef]{1}/, :start=>8,:end=>1}, human_readable)
9
+ end
10
+
11
+ def relief(human_readable=false)
12
+ relief_map = {'a'=>'Contours', 'b'=>'Shading', 'c'=>'Grading and bathymetric tints',
13
+ 'd'=>'Hachures', 'e'=>'Bathymetry, soundings', 'f'=>'Form lines', 'g'=>'Spot heights',
14
+ 'h'=>'Color', 'i'=>'Pictorially', 'j'=>'Land forms', 'k'=>'Bathymetry, isolines',
15
+ 'm'=>'Rock drawings', 'z'=>'Other'
16
+ }
17
+ contents = []
18
+ if self.record_type == 'MAP'
19
+ self['008'].value[18,4].split(//).each { | char |
20
+ next if char == " "
21
+ if human_readable
22
+ contents << relief_map[char]
23
+ else
24
+ contents << char
25
+ end
26
+ }
27
+ end
28
+ @fields.find_all {|f| ('006') === f.tag}.each { | fxd_fld |
29
+ next unless fxd_fld.value[0,1].match(/[ef]{1}/)
30
+ fxd_fld.value[1,4].split(//).each { | char |
31
+ next if char == " "
32
+ if human_readable
33
+ contents << relief_map[char]
34
+ else
35
+ contents << char
36
+ end
37
+ }
38
+ }
39
+ return false if contents.empty?
40
+ return contents
41
+ end
42
+
43
+ def projection(human_readable=false)
44
+ proj_map = {'Azimuthal'=>{'aa'=>'Aitoff','ab'=>'Gnomic','ac'=>"Lambert's equal area",
45
+ 'ad'=>'Orthographic','ae'=>'Azithumal equidistant', 'af'=>'Stereographic',
46
+ 'ag'=>'General vertical near-sided','am'=>'Modified stereographic for Alaska',
47
+ 'an'=>'Chamberlin trimetric','ap'=>'Polar stereographic','au'=>'Unknown','az'=>'Other'},
48
+ 'Cylindrical'=>{'ba'=>'Gall','bb'=>"Goode's homolographic",'bc'=>"Lambert's equal area",
49
+ 'bd'=>'Mercator','be'=>'Miller','bf'=>'Mollweide','bg'=>'Sinusoidal',
50
+ 'bh'=>'Transverse Mercator','bi'=>'Gauss-Kruger','bj'=>'Equirectangular',
51
+ 'bo'=>'Oblique Mercator','br'=>'Robinson','bs'=>'Space oblique Mercator',
52
+ 'bu'=>'Unknown','bz'=>'Other'
53
+ },
54
+ 'Conic'=>{'ca'=>"Alber's equal area",'cb'=>'Bonne','cc'=>"Lambert's",'ce'=>'Equidistant conic',
55
+ 'cp'=>'Polyconic','cu'=>'Unknown','cz'=>'Other'
56
+ },
57
+ 'Other'=>{'da'=>'Armadillo','db'=>'Butterfly','dc'=>'Eckert','dd'=>"Goode's homolosine",
58
+ 'de'=>"Miller's bipolar oblique conformal conic",'df'=>'Van Der Grinten',
59
+ 'dg'=>'Dymaxion','dh'=>'Cordiform','dl'=>'Lambert conformal','zz'=>'Other'
60
+ }
61
+ }
62
+ if @record_type == "MAP"
63
+ unless self['008'].value[22,2] == ' '
64
+ if human_readable
65
+ proj_map.each_key { | general |
66
+ next unless proj_map[general].keys.index(self['008'].value[22,2])
67
+ return [general,proj_map[general][self['008'].value[22,2]]]
68
+ }
69
+ else
70
+ return self['008'].value[22,2]
71
+ end
72
+ end
73
+ end
74
+ @fields.find_all {|f| ('006') === f.tag}.each { | fxd_fld |
75
+ next unless fxd_fld.value[0,1].match(/[ef]{1}/)
76
+ unless fxd_fld.value[5,2] == ' '
77
+ if human_readable
78
+ proj_map.each_key { | general |
79
+ next unless proj_map[general].keys.index(fxd_fld.value[5,2])
80
+ return [general,proj_map[general][fxd_fld.value[5,2]]]
81
+ }
82
+ else
83
+ return fxd_fld.value[5,2]
84
+ end
85
+ end
86
+ }
87
+ return false
88
+ end
89
+
90
+ def special_format(human_readable=false)
91
+ spfm_map = {'a'=>'Blueprint photocopy','b'=>'Other photocopy','c'=>'Negative photocopy',
92
+ 'd'=>'Film negative','f'=>'Facsimile','g'=>'Relief model','h'=>'Rare (pre-1800)',
93
+ 'e'=>'Manuscript','j'=>'Picture/post card','k'=>'Calendar','l'=>'Puzzle',
94
+ 'm'=>'Braille, tactile','n'=>'Game','o'=>'Wall map','p'=>'Playing cards',
95
+ 'q'=>'Loose-leaf','z'=>'Other'}
96
+ human_readable = spfm_map if human_readable
97
+ return self.field_parser({:match=>'MAP', :start=>33,:end=>2}, {:match=>/[ef]{1}/, :start=>16,:end=>2}, human_readable)
98
+ end
99
+ end
@@ -0,0 +1,37 @@
1
+ module MARC
2
+
3
+ # A class that represents an individual MARC record. Every record
4
+ # is made up of a collection of MARC::Field objects.
5
+
6
+ class MixedRecord < Record
7
+
8
+ def initialize
9
+ super
10
+ @leader[6] = 'p' if @leader[6,1] == ' '
11
+ @leader[7] = 'c' if @leader[7,1] == ' '
12
+ @record_type = 'MIX'
13
+ @bibliographic_level = @leader.get_blvl
14
+ self.extend MixedType
15
+ self.inspect_fixed_fields
16
+ end
17
+
18
+ def is_valid_type?
19
+ return false unless @leader[6,1].match('p')
20
+ return true
21
+ end
22
+ def is_valid_blvl?
23
+ return false unless @leader[7,1].match(/[cdi]{1}/)
24
+ return true
25
+ end
26
+ def self.new_from_record(record)
27
+ rec = MixedRecord.new
28
+ record.instance_variables.each { | var |
29
+ rec.instance_variable_set(var, record.instance_variable_get(var))
30
+ }
31
+ return Exception.new("Incorrect type declaration in leader") unless rec.is_valid_type?
32
+ return Exception.new("Incorrect bibliographic declaration in leader") unless rec.is_valid_blvl?
33
+ return rec
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,4 @@
1
+ module MixedType
2
+ include RecordType
3
+ public :form
4
+ end
@@ -0,0 +1,105 @@
1
+ module MARC
2
+ class Reader
3
+ # A static method for turning raw MARC data in transission
4
+ # format into a MARC::Record object.
5
+ def self.decode(marc, params={})
6
+ leader = Leader.new(marc[0..LEADER_LENGTH-1])
7
+ begin
8
+ record = case leader.get_type
9
+ when 'BKS' then MARC::BookRecord.new
10
+ when 'SER' then MARC::SerialRecord.new
11
+ when 'VIS' then MARC::VisualRecord.new
12
+ when 'MIX' then MARC::MixedRecord.new
13
+ when 'MAP' then MARC::MapRecord.new
14
+ when 'SCO' then MARC::ScoreRecord.new
15
+ when 'REC' then MARC::SoundRecord.new
16
+ when 'COM' then MARC::ComputerRecord.new
17
+ else MARC::Record.new
18
+ end
19
+ rescue ArgumentError
20
+ record = MARC::Record.new
21
+ end
22
+ record.leader = leader
23
+
24
+ # where the field data starts
25
+ base_address = record.leader[12..16].to_i
26
+
27
+ # get the byte offsets from the record directory
28
+ directory = marc[LEADER_LENGTH..base_address-1]
29
+
30
+ throw "invalid directory in record" if directory == nil
31
+
32
+ # the number of fields in the record corresponds to
33
+ # how many directory entries there are
34
+ num_fields = directory.length / DIRECTORY_ENTRY_LENGTH
35
+
36
+ # when operating in forgiving mode we just split on end of
37
+ # field instead of using calculated byte offsets from the
38
+ # directory
39
+ all_fields = marc[base_address..-1].split(END_OF_FIELD)
40
+
41
+ 0.upto(num_fields-1) do |field_num|
42
+
43
+ # pull the directory entry for a field out
44
+ entry_start = field_num * DIRECTORY_ENTRY_LENGTH
45
+ entry_end = entry_start + DIRECTORY_ENTRY_LENGTH
46
+ entry = directory[entry_start..entry_end]
47
+
48
+ # extract the tag
49
+ tag = entry[0..2]
50
+
51
+ # get the actual field data
52
+ # if we were told to be forgiving we just use the
53
+ # next available chuck of field data that we
54
+ # split apart based on the END_OF_FIELD
55
+ field_data = ''
56
+ if params[:forgiving]
57
+ field_data = all_fields.shift()
58
+
59
+ # otherwise we actually use the byte offsets in
60
+ # directory to figure out what field data to extract
61
+ else
62
+ length = entry[3..6].to_i
63
+ offset = entry[7..11].to_i
64
+ field_start = base_address + offset
65
+ field_end = field_start + length - 1
66
+ field_data = marc[field_start..field_end]
67
+ end
68
+
69
+ # remove end of field
70
+ field_data.delete!(END_OF_FIELD)
71
+
72
+ # add a control field or data field
73
+ if tag < '010'
74
+ record.append(MARC::ControlField.new(tag,field_data))
75
+ else
76
+ field = MARC::DataField.new(tag)
77
+
78
+ # get all subfields
79
+ subfields = field_data.split(SUBFIELD_INDICATOR)
80
+
81
+ # must have at least 2 elements (indicators, and 1 subfield)
82
+ # TODO some sort of logging?
83
+ next if subfields.length() < 2
84
+
85
+ # get indicators
86
+ indicators = subfields.shift()
87
+ field.indicator1 = indicators[0,1]
88
+ field.indicator2 = indicators[1,1]
89
+
90
+ # add each subfield to the field
91
+ subfields.each() do |data|
92
+ subfield = MARC::Subfield.new(data[0,1],data[1..-1])
93
+ field.append(subfield)
94
+ end
95
+
96
+ # add the field to the record
97
+ record.append(field)
98
+ end
99
+ end
100
+
101
+ return record
102
+ end
103
+
104
+ end
105
+ end
@@ -0,0 +1,96 @@
1
+ module MARC
2
+ class Record
3
+
4
+ attr_reader :record_type, :bibliographic_level
5
+
6
+ # Creates a new MARC::Record using MARC::Leader
7
+ # to work with the leader, rather than a string
8
+ def initialize
9
+ @fields = []
10
+ @leader = Leader.new(' ' * 24)
11
+ end
12
+
13
+ def contains_type?(record_type)
14
+ type_map = {"BKS"=>/[at]{1}/, "COM"=>"m", "MAP"=>/[ef]{1}/,"MIX"=>"p", "SCO"=>/[cd]{1}/, "REC"=>/[ij]{1}/, "SER"=>"s", "VIS"=>/[gkor]{1}/}
15
+ matching_fields = []
16
+ @fields.find_all {|f| ('006') === f.tag}.each { | fxd_fld |
17
+ matching_fields << fxd_fld if fxd_fld.value[0,1].match(type_map[record_type])
18
+
19
+ }
20
+ return nil if matching_fields.empty?
21
+ return matching_fields
22
+ end
23
+
24
+ def self.new_from_record(record)
25
+ leader = Leader.new(record.leader)
26
+ case leader.get_type
27
+ when 'BKS' then return MARC::BookRecord.new_from_record(record)
28
+ when 'SER' then return MARC::SerialRecord.new_from_record(record)
29
+ when 'VIS' then return MARC::VisualRecord.new_from_record(record)
30
+ when 'MIX' then return MARC::MixedRecord.new_from_record(record)
31
+ when 'MAP' then return MARC::MapRecord.new_from_record(record)
32
+ when 'SCO' then return MARC::ScoreRecord.new_from_record(record)
33
+ when 'REC' then return MARC::SoundRecord.new_from_record(record)
34
+ when 'COM' then return MARC::ComputerRecord.new_from_record(record)
35
+ end
36
+ end
37
+
38
+ def to_typed_record
39
+ return self.new_from_record(self)
40
+ end
41
+
42
+ def is_archival?
43
+ return @leader.is_archival?
44
+ end
45
+
46
+
47
+ def composition_form(human_readable=false)
48
+ end
49
+
50
+
51
+ def publication_country
52
+ return self['008'].value[15,2] unless self['008'].value[15,2] == ' '
53
+ return false
54
+ end
55
+
56
+ def get_dates
57
+
58
+ end
59
+
60
+ def created_on
61
+ unless self['008'].value[0,6] == (' '*6)
62
+ return Date.parse(self['008'].value[0,2]+'-'+self['008'].value[2,2]+'-'+self['008'].value[4,2], false)
63
+ else
64
+ return Date.today
65
+ end
66
+ end
67
+
68
+ def inspect_fixed_fields
69
+ type_map = {/[at]{1}/=>BookType,'m'=>ComputerType,/[ef]{1}/=>MapType,
70
+ 'p'=>MixedType,/[cd]{1}/=>ScoreType,/[ij]{1}/=>SoundType,'s'=>SerialType,
71
+ /[gkor]{1}/=>VisualType}
72
+ @fields.find_all {|f| ('006') === f.tag}.each { | fxd_fld |
73
+ type_map.each_key { | key |
74
+ if fxd_fld.value[0,1].match(key)
75
+ self.extend type_map[key]
76
+ end
77
+ }
78
+ }
79
+ end
80
+
81
+ def languages
82
+ languages = []
83
+ unless self['008'].value[35,3].empty?
84
+ languages << Locale::Info.get_language(self['008'].value[35,3])
85
+ end
86
+ oh_four_ones = @fields.find_all {|fld| fld.tag == "041"}
87
+ oh_four_ones.each do | oh_four_one |
88
+ langs = oh_four_one.find_all { |sub| sub.code == 'a'}
89
+ langs.each do | lang |
90
+ languages << Locale::Info.get_language(lang.value)
91
+ end
92
+ end
93
+ languages
94
+ end
95
+ end
96
+ end