enhanced_marc 0.1.5

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 (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