1 # $Id: reader.rb,v 1.12 2011/12/15 02:20:43 machan Exp $
2
3 require 'tmdoc/tmstd'
4 require 'tmdoc/constant'
5 require 'tmdoc/environment'
6 require 'tmdoc/model/core'
7 require 'tmdoc/reader/ruby1.8/scanner'
8 require 'tmdoc/reader/ruby1.8/parser'
9
10
11 module TmDoc
12
13 module Reader
14
15 class FileItem < TmStd::Lsm::Product::Abstract
16 include Comparable
17
18 attr_reader :expand_path, :name, :index
19 attr_reader :hash
20
21
22 def initialize(expand_path, name, index)
23 ASSERT.kind_of expand_path, String
24 ASSERT.kind_of name, String
25 ASSERT.kind_of index, Integer
26
27 @expand_path = expand_path
28 @name = name
29 @index = index
30
31 @expand_path.freeze
32 @hash = self.expand_path.hash
33 end
34
35
36 def eql?(other)
37 result = self.class >= other.class &&
38 self.expand_path == other.expand_path
39
40 ASSERT.boolean result
41 end
42
43
44 def freeze_equality!
45 nil # Nop, already frozen.
46 end
47
48
49 def <=>(other)
50 ASSERT.kind_of other, FileItem
51
52 result = self.index <=> other.index
53
54 ASSERT.kind_of result, Integer
55 end
56 end
57
58
59 class SetOfFileItem < TmStd::Lsm::Collection::Set::Abstract
60 LSM_ELEMENT_CLASS = FileItem
61 end
62
63
64 def self.read(dir_name, file_names, env, &logger)
65 ASSERT.kind_of dir_name, String
66 ASSERT.kind_of file_names, LSM::SeqOfString
67 ASSERT.kind_of env, ENV::Environment
68 ASSERT.opt_kind_of logger, Proc
69
70 LOG::Debug.msgout "CALLED" if env.debug?
71
72 set_of_file_item = file_names.map_with_index { |file_name, index|
73 [file_name, index]
74 }.inject(SetOfFileItem.new) { |set, pair|
75 ASSERT.tuple_of pair, [String, Integer]
76 file_name, index = pair
77
78 expand_file_path = self.check_file dir_name, file_name, env
79 if expand_file_path
80 file_item = FileItem.new(
81 expand_file_path, file_name, index
82 )
83
84 unless set.include?(file_item)
85 set << file_item
86 else
87 LOG::Error.log(
88 "Source file duplication: '%s'", expand_file_path
89 )
90 CMD.test_sensitive_level env, LOG::Error
91
92 set
93 end
94 else
95 set
96 end
97 }
98
99 mc_array_of_file = set_of_file_item.sort.map { |file_item|
100 file_name = file_item.name
101 logger.call(file_name) if logger
102
103 mc_toplevel_module = self.read_source(
104 file_item.expand_path, file_name, env
105 )
106
107 if mc_toplevel_module
108 MCP::File.new(
109 file_name, file_item.index, mc_toplevel_module
110 )
111 else
112 nil
113 end
114 }.compact
115
116 if mc_array_of_file.empty?
117 LOG::Error.log "None applicatable source file."
118 CMD.test_sensitive_level env, LOG::Error
119 end
120
121 MC::Store.new MCP::SetOfFile.new(mc_array_of_file)
122 end
123
124
125 def self.read_source(expand_file_path, input_file_name, env)
126 ASSERT.kind_of expand_file_path, String
127 ASSERT.kind_of input_file_name, String
128 ASSERT.kind_of env, ENV::Environment
129
130 mc_toplevel_module = nil
131 begin
132 File.open(expand_file_path) do |input|
133 mc_toplevel_module = Ruby18::Parser.parse(
134 Ruby18::Scanner.new(input, env, input_file_name), env
135 )
136 end
137 rescue SystemCallError => exception
138 LOG::Error.log(
139 "System call error in reading file\n" + "\t%s (%s)",
140 exception.to_s, exception.class.to_s
141 )
142 CMD.test_sensitive_level env, LOG::Error
143 rescue IOError => exception
144 LOG::Error.log "I/O error: '%s'", expand_file_path
145 CMD.test_sensitive_level env, LOG::Error
146 end
147
148 mc_toplevel_module
149
150 ASSERT.opt_kind_of mc_toplevel_module, MCLN::ToplevelModule
151 end
152
153
154 def self.check_file(dir_name, file_name, env)
155 ASSERT.opt_kind_of dir_name, String
156 ASSERT.opt_kind_of file_name, String
157 ASSERT.kind_of env, ENV::Environment
158
159 current_file_path = File.expand_path './' + file_name
160 expand_file_path = File.expand_path dir_name + '/' + file_name
161
162 if current_file_path != expand_file_path
163 if self.valid_file_path?(
164 current_file_path, file_name, env, false
165 )
166 return ASSERT.kind_of current_file_path, String
167 end
168 end
169
170 if self.valid_file_path?(expand_file_path, file_name, env)
171 return ASSERT.kind_of expand_file_path, String
172 end
173
174 nil
175 end
176
177
178 def self.valid_file_path?(file_path, file_name, env, does_log = true)
179 ASSERT.opt_kind_of file_path, String
180 ASSERT.opt_kind_of file_name, String
181 ASSERT.kind_of env, ENV::Environment
182 ASSERT.boolean does_log
183
184 unless File.exist?(file_path)
185 if does_log
186 LOG::Error.log "No such file: '%s'", file_path
187 CMD.test_sensitive_level env, LOG::Error
188 end
189
190 return false
191 end
192
193 file_stat = File.stat(file_path)
194 ASSERT.kind_of file_stat, File::Stat
195
196 unless file_stat.file?
197 if does_log
198 LOG::Error.log "Not a regular file: '%s'", file_path
199 CMD.test_sensitive_level env, LOG::Error
200 end
201
202 return false
203 end
204
205 unless file_stat.readable?
206 if does_log
207 LOG::Error.log "Not a readable file: '%s'", file_path
208 CMD.test_sensitive_level env, LOG::Error
209 end
210
211 return false
212 end
213
214 true
215 end
216 end
217
218 end # TmDoc