@@ -38,125 +38,159 @@ impl fmt::Display for ConstantPathError {
3838
3939impl std:: error:: Error for ConstantPathError { }
4040
41- impl < ' pr > ConstantReadNode < ' pr > {
41+ /// Trait for nodes that can compute their full constant name.
42+ ///
43+ /// Implemented by constant-related nodes (`ConstantReadNode`,
44+ /// `ConstantWriteNode`, `ConstantTargetNode`, `ConstantPathNode`, and
45+ /// `ConstantPathTargetNode`).
46+ pub trait FullName < ' pr > {
47+ /// Returns the list of parts for the full name of this constant.
48+ ///
49+ /// # Errors
50+ ///
51+ /// Returns [`ConstantPathError`] if the path contains dynamic parts or
52+ /// missing nodes.
53+ fn full_name_parts ( & self ) -> Result < Vec < & ' pr [ u8 ] > , ConstantPathError > ;
54+
55+ /// Returns the full name of this constant.
56+ ///
57+ /// # Errors
58+ ///
59+ /// Returns [`ConstantPathError`] if the path contains dynamic parts or
60+ /// missing nodes.
61+ fn full_name ( & self ) -> Result < Vec < u8 > , ConstantPathError > {
62+ let parts = self . full_name_parts ( ) ?;
63+ let mut result = Vec :: new ( ) ;
64+ for ( i, part) in parts. iter ( ) . enumerate ( ) {
65+ if i > 0 {
66+ result. extend_from_slice ( b"::" ) ;
67+ }
68+ result. extend_from_slice ( part) ;
69+ }
70+ Ok ( result)
71+ }
72+ }
73+
74+ /// Computes `full_name_parts` for a `Node` by dispatching to the appropriate
75+ /// `FullName` implementation.
76+ fn full_name_parts_for_node < ' pr > ( node : & Node < ' pr > ) -> Result < Vec < & ' pr [ u8 ] > , ConstantPathError > {
77+ node. as_constant_path_node ( )
78+ . map_or_else ( || node. as_constant_read_node ( ) . map_or ( Err ( ConstantPathError :: DynamicParts ) , |read_node| read_node. full_name_parts ( ) ) , |path_node| path_node. full_name_parts ( ) )
79+ }
80+
81+ impl < ' pr > FullName < ' pr > for ConstantReadNode < ' pr > {
4282 /// Returns the list of parts for the full name of this constant.
4383 ///
4484 /// # Examples
4585 ///
4686 /// ```
47- /// # use ruby_prism::parse;
87+ /// # use ruby_prism::{ parse, FullName} ;
4888 /// let result = parse(b"Foo");
4989 /// let stmt = result.node().as_program_node().unwrap()
5090 /// .statements().body().iter().next().unwrap();
5191 /// let constant = stmt.as_constant_read_node().unwrap();
52- /// assert_eq!(constant.full_name_parts(), vec![b"Foo".as_slice()]);
92+ /// assert_eq!(constant.full_name_parts().unwrap() , vec![b"Foo".as_slice()]);
5393 /// ```
54- #[ must_use]
55- pub fn full_name_parts ( & self ) -> Vec < & ' pr [ u8 ] > {
56- vec ! [ self . name( ) . as_slice( ) ]
94+ fn full_name_parts ( & self ) -> Result < Vec < & ' pr [ u8 ] > , ConstantPathError > {
95+ Ok ( vec ! [ self . name( ) . as_slice( ) ] )
5796 }
5897
5998 /// Returns the full name of this constant.
6099 ///
61100 /// # Examples
62101 ///
63102 /// ```
64- /// # use ruby_prism::parse;
103+ /// # use ruby_prism::{ parse, FullName} ;
65104 /// let result = parse(b"Foo");
66105 /// let stmt = result.node().as_program_node().unwrap()
67106 /// .statements().body().iter().next().unwrap();
68107 /// let constant = stmt.as_constant_read_node().unwrap();
69- /// assert_eq!(constant.full_name(), b"Foo");
108+ /// assert_eq!(constant.full_name().unwrap() , b"Foo");
70109 /// ```
71- #[ must_use]
72- pub fn full_name ( & self ) -> & ' pr [ u8 ] {
73- self . name ( ) . as_slice ( )
110+ fn full_name ( & self ) -> Result < Vec < u8 > , ConstantPathError > {
111+ Ok ( self . name ( ) . as_slice ( ) . to_vec ( ) )
74112 }
75113}
76114
77- impl < ' pr > ConstantWriteNode < ' pr > {
115+ impl < ' pr > FullName < ' pr > for ConstantWriteNode < ' pr > {
78116 /// Returns the list of parts for the full name of this constant.
79117 ///
80118 /// # Examples
81119 ///
82120 /// ```
83- /// # use ruby_prism::parse;
121+ /// # use ruby_prism::{ parse, FullName} ;
84122 /// let result = parse(b"Foo = 1");
85123 /// let stmt = result.node().as_program_node().unwrap()
86124 /// .statements().body().iter().next().unwrap();
87125 /// let constant = stmt.as_constant_write_node().unwrap();
88- /// assert_eq!(constant.full_name_parts(), vec![b"Foo".as_slice()]);
126+ /// assert_eq!(constant.full_name_parts().unwrap() , vec![b"Foo".as_slice()]);
89127 /// ```
90- #[ must_use]
91- pub fn full_name_parts ( & self ) -> Vec < & ' pr [ u8 ] > {
92- vec ! [ self . name( ) . as_slice( ) ]
128+ fn full_name_parts ( & self ) -> Result < Vec < & ' pr [ u8 ] > , ConstantPathError > {
129+ Ok ( vec ! [ self . name( ) . as_slice( ) ] )
93130 }
94131
95132 /// Returns the full name of this constant.
96133 ///
97134 /// # Examples
98135 ///
99136 /// ```
100- /// # use ruby_prism::parse;
137+ /// # use ruby_prism::{ parse, FullName} ;
101138 /// let result = parse(b"Foo = 1");
102139 /// let stmt = result.node().as_program_node().unwrap()
103140 /// .statements().body().iter().next().unwrap();
104141 /// let constant = stmt.as_constant_write_node().unwrap();
105- /// assert_eq!(constant.full_name(), b"Foo");
142+ /// assert_eq!(constant.full_name().unwrap() , b"Foo");
106143 /// ```
107- #[ must_use]
108- pub fn full_name ( & self ) -> & ' pr [ u8 ] {
109- self . name ( ) . as_slice ( )
144+ fn full_name ( & self ) -> Result < Vec < u8 > , ConstantPathError > {
145+ Ok ( self . name ( ) . as_slice ( ) . to_vec ( ) )
110146 }
111147}
112148
113- impl < ' pr > ConstantTargetNode < ' pr > {
149+ impl < ' pr > FullName < ' pr > for ConstantTargetNode < ' pr > {
114150 /// Returns the list of parts for the full name of this constant.
115151 ///
116152 /// # Examples
117153 ///
118154 /// ```
119- /// # use ruby_prism::parse;
155+ /// # use ruby_prism::{ parse, FullName} ;
120156 /// let result = parse(b"Foo, Bar = [1, 2]");
121157 /// let stmt = result.node().as_program_node().unwrap()
122158 /// .statements().body().iter().next().unwrap();
123159 /// let target = stmt.as_multi_write_node().unwrap()
124160 /// .lefts().iter().next().unwrap();
125161 /// let constant = target.as_constant_target_node().unwrap();
126- /// assert_eq!(constant.full_name_parts(), vec![b"Foo".as_slice()]);
162+ /// assert_eq!(constant.full_name_parts().unwrap() , vec![b"Foo".as_slice()]);
127163 /// ```
128- #[ must_use]
129- pub fn full_name_parts ( & self ) -> Vec < & ' pr [ u8 ] > {
130- vec ! [ self . name( ) . as_slice( ) ]
164+ fn full_name_parts ( & self ) -> Result < Vec < & ' pr [ u8 ] > , ConstantPathError > {
165+ Ok ( vec ! [ self . name( ) . as_slice( ) ] )
131166 }
132167
133168 /// Returns the full name of this constant.
134169 ///
135170 /// # Examples
136171 ///
137172 /// ```
138- /// # use ruby_prism::parse;
173+ /// # use ruby_prism::{ parse, FullName} ;
139174 /// let result = parse(b"Foo, Bar = [1, 2]");
140175 /// let stmt = result.node().as_program_node().unwrap()
141176 /// .statements().body().iter().next().unwrap();
142177 /// let target = stmt.as_multi_write_node().unwrap()
143178 /// .lefts().iter().next().unwrap();
144179 /// let constant = target.as_constant_target_node().unwrap();
145- /// assert_eq!(constant.full_name(), b"Foo");
180+ /// assert_eq!(constant.full_name().unwrap() , b"Foo");
146181 /// ```
147- #[ must_use]
148- pub fn full_name ( & self ) -> & ' pr [ u8 ] {
149- self . name ( ) . as_slice ( )
182+ fn full_name ( & self ) -> Result < Vec < u8 > , ConstantPathError > {
183+ Ok ( self . name ( ) . as_slice ( ) . to_vec ( ) )
150184 }
151185}
152186
153- impl < ' pr > ConstantPathNode < ' pr > {
187+ impl < ' pr > FullName < ' pr > for ConstantPathNode < ' pr > {
154188 /// Returns the list of parts for the full name of this constant path.
155189 ///
156190 /// # Examples
157191 ///
158192 /// ```
159- /// # use ruby_prism::parse;
193+ /// # use ruby_prism::{ parse, FullName} ;
160194 /// let result = parse(b"Foo::Bar");
161195 /// let stmt = result.node().as_program_node().unwrap()
162196 /// .statements().body().iter().next().unwrap();
@@ -169,84 +203,26 @@ impl<'pr> ConstantPathNode<'pr> {
169203 /// Returns [`ConstantPathError::DynamicParts`] if the path contains
170204 /// dynamic parts, or [`ConstantPathError::MissingNodes`] if the path
171205 /// contains missing nodes.
172- pub fn full_name_parts ( & self ) -> Result < Vec < & ' pr [ u8 ] > , ConstantPathError > {
173- let mut parts = Vec :: new ( ) ;
174- let mut current: Option < Node < ' pr > > = Some ( self . as_node ( ) ) ;
175-
176- while let Some ( ref node) = current {
177- if let Some ( path_node) = node. as_constant_path_node ( ) {
178- let name = path_node. name ( ) . ok_or ( ConstantPathError :: MissingNodes ) ?;
179- parts. push ( name. as_slice ( ) ) ;
180- current = path_node. parent ( ) ;
181- } else if let Some ( read_node) = node. as_constant_read_node ( ) {
182- parts. push ( read_node. name ( ) . as_slice ( ) ) ;
183- current = None ;
184- } else {
185- return Err ( ConstantPathError :: DynamicParts ) ;
186- }
187- }
188-
189- parts. reverse ( ) ;
206+ fn full_name_parts ( & self ) -> Result < Vec < & ' pr [ u8 ] > , ConstantPathError > {
207+ let name = self . name ( ) . ok_or ( ConstantPathError :: MissingNodes ) ?;
190208
191- if self . is_stovetop ( ) {
192- parts. insert ( 0 , b"" . as_slice ( ) ) ;
193- }
209+ let mut parts = match self . parent ( ) {
210+ Some ( ref parent) => full_name_parts_for_node ( parent) ?,
211+ None => vec ! [ b"" . as_slice( ) ] ,
212+ } ;
194213
214+ parts. push ( name. as_slice ( ) ) ;
195215 Ok ( parts)
196216 }
197-
198- /// Returns the full name of this constant path.
199- ///
200- /// # Examples
201- ///
202- /// ```
203- /// # use ruby_prism::parse;
204- /// let result = parse(b"Foo::Bar");
205- /// let stmt = result.node().as_program_node().unwrap()
206- /// .statements().body().iter().next().unwrap();
207- /// let constant_path = stmt.as_constant_path_node().unwrap();
208- /// assert_eq!(constant_path.full_name().unwrap(), b"Foo::Bar");
209- /// ```
210- ///
211- /// # Errors
212- ///
213- /// Returns [`ConstantPathError::DynamicParts`] if the path contains
214- /// dynamic parts, or [`ConstantPathError::MissingNodes`] if the path
215- /// contains missing nodes.
216- pub fn full_name ( & self ) -> Result < Vec < u8 > , ConstantPathError > {
217- let parts = self . full_name_parts ( ) ?;
218- let mut result = Vec :: new ( ) ;
219- for ( i, part) in parts. iter ( ) . enumerate ( ) {
220- if i > 0 {
221- result. extend_from_slice ( b"::" ) ;
222- }
223- result. extend_from_slice ( part) ;
224- }
225- Ok ( result)
226- }
227-
228- fn is_stovetop ( & self ) -> bool {
229- let mut current: Option < Node < ' pr > > = Some ( self . as_node ( ) ) ;
230-
231- while let Some ( ref node) = current {
232- if let Some ( path_node) = node. as_constant_path_node ( ) {
233- current = path_node. parent ( ) ;
234- } else {
235- return false ;
236- }
237- }
238-
239- true
240- }
241217}
242218
243- impl < ' pr > ConstantPathTargetNode < ' pr > {
219+ impl < ' pr > FullName < ' pr > for ConstantPathTargetNode < ' pr > {
244220 /// Returns the list of parts for the full name of this constant path.
245221 ///
246222 /// # Examples
247223 ///
248224 /// ```
249- /// # use ruby_prism::parse;
225+ /// # use ruby_prism::{ parse, FullName} ;
250226 /// let result = parse(b"Foo::Bar, Baz = [1, 2]");
251227 /// let stmt = result.node().as_program_node().unwrap()
252228 /// .statements().body().iter().next().unwrap();
@@ -261,61 +237,22 @@ impl<'pr> ConstantPathTargetNode<'pr> {
261237 /// Returns [`ConstantPathError::DynamicParts`] if the path contains
262238 /// dynamic parts, or [`ConstantPathError::MissingNodes`] if the path
263239 /// contains missing nodes.
264- pub fn full_name_parts ( & self ) -> Result < Vec < & ' pr [ u8 ] > , ConstantPathError > {
240+ fn full_name_parts ( & self ) -> Result < Vec < & ' pr [ u8 ] > , ConstantPathError > {
265241 let name = self . name ( ) . ok_or ( ConstantPathError :: MissingNodes ) ?;
266242
267- let mut parts = if let Some ( parent) = self . parent ( ) {
268- if let Some ( path_node) = parent. as_constant_path_node ( ) {
269- path_node. full_name_parts ( ) ?
270- } else if let Some ( read_node) = parent. as_constant_read_node ( ) {
271- read_node. full_name_parts ( )
272- } else {
273- return Err ( ConstantPathError :: DynamicParts ) ;
274- }
275- } else {
276- vec ! [ b"" . as_slice( ) ]
243+ let mut parts = match self . parent ( ) {
244+ Some ( ref parent) => full_name_parts_for_node ( parent) ?,
245+ None => vec ! [ b"" . as_slice( ) ] ,
277246 } ;
278247
279248 parts. push ( name. as_slice ( ) ) ;
280249 Ok ( parts)
281250 }
282-
283- /// Returns the full name of this constant path.
284- ///
285- /// # Examples
286- ///
287- /// ```
288- /// # use ruby_prism::parse;
289- /// let result = parse(b"Foo::Bar, Baz = [1, 2]");
290- /// let stmt = result.node().as_program_node().unwrap()
291- /// .statements().body().iter().next().unwrap();
292- /// let target = stmt.as_multi_write_node().unwrap()
293- /// .lefts().iter().next().unwrap();
294- /// let constant_path = target.as_constant_path_target_node().unwrap();
295- /// assert_eq!(constant_path.full_name().unwrap(), b"Foo::Bar");
296- /// ```
297- ///
298- /// # Errors
299- ///
300- /// Returns [`ConstantPathError::DynamicParts`] if the path contains
301- /// dynamic parts, or [`ConstantPathError::MissingNodes`] if the path
302- /// contains missing nodes.
303- pub fn full_name ( & self ) -> Result < Vec < u8 > , ConstantPathError > {
304- let parts = self . full_name_parts ( ) ?;
305- let mut result = Vec :: new ( ) ;
306- for ( i, part) in parts. iter ( ) . enumerate ( ) {
307- if i > 0 {
308- result. extend_from_slice ( b"::" ) ;
309- }
310- result. extend_from_slice ( part) ;
311- }
312- Ok ( result)
313- }
314251}
315252
316253#[ cfg( test) ]
317254mod tests {
318- use super :: ConstantPathError ;
255+ use super :: { ConstantPathError , FullName } ;
319256 use crate :: parse;
320257
321258 #[ test]
@@ -324,8 +261,8 @@ mod tests {
324261 let node = result. node ( ) . as_program_node ( ) . unwrap ( ) . statements ( ) . body ( ) . iter ( ) . next ( ) . unwrap ( ) ;
325262 let constant = node. as_constant_read_node ( ) . unwrap ( ) ;
326263
327- assert_eq ! ( constant. full_name_parts( ) , vec![ b"Foo" . as_slice( ) ] ) ;
328- assert_eq ! ( constant. full_name( ) , b"Foo" ) ;
264+ assert_eq ! ( constant. full_name_parts( ) . unwrap ( ) , vec![ b"Foo" . as_slice( ) ] ) ;
265+ assert_eq ! ( constant. full_name( ) . unwrap ( ) , b"Foo" ) ;
329266 }
330267
331268 #[ test]
@@ -334,8 +271,8 @@ mod tests {
334271 let node = result. node ( ) . as_program_node ( ) . unwrap ( ) . statements ( ) . body ( ) . iter ( ) . next ( ) . unwrap ( ) ;
335272 let constant = node. as_constant_write_node ( ) . unwrap ( ) ;
336273
337- assert_eq ! ( constant. full_name_parts( ) , vec![ b"Foo" . as_slice( ) ] ) ;
338- assert_eq ! ( constant. full_name( ) , b"Foo" ) ;
274+ assert_eq ! ( constant. full_name_parts( ) . unwrap ( ) , vec![ b"Foo" . as_slice( ) ] ) ;
275+ assert_eq ! ( constant. full_name( ) . unwrap ( ) , b"Foo" ) ;
339276 }
340277
341278 #[ test]
@@ -346,8 +283,8 @@ mod tests {
346283 let target = multi_write. lefts ( ) . iter ( ) . next ( ) . unwrap ( ) ;
347284 let constant = target. as_constant_target_node ( ) . unwrap ( ) ;
348285
349- assert_eq ! ( constant. full_name_parts( ) , vec![ b"Foo" . as_slice( ) ] ) ;
350- assert_eq ! ( constant. full_name( ) , b"Foo" ) ;
286+ assert_eq ! ( constant. full_name_parts( ) . unwrap ( ) , vec![ b"Foo" . as_slice( ) ] ) ;
287+ assert_eq ! ( constant. full_name( ) . unwrap ( ) , b"Foo" ) ;
351288 }
352289
353290 #[ test]
0 commit comments