tfpt review /shelveset:merge-3;REDMOND\jflam Ruby only This shelveset fixes a number of open bugs on Rubyforge and adds some features that we need to get the latest rubinius specs running. MatchDataOps: - we used to alias MatchData to System.Text.RegularExpressions.Match. However, to fully implement MatchData we need to also hold onto a reference to the original string that we matched against. A new MatchData type was created (MatchData.cs) which wraps the existing .NET Match object. This also touches MutableStringOps.cs, RubyOps.cs, RubyScope.cs, SpecialGlobalVariableInfo.cs - finished implementing all methods. 16 out of 16 specs pass - implemented to_a which closes bug #19903 RegexpOps: - added ctor overload to close bug #19927 - made some changes to return MatchData objects instead of Match objects - made some changes to return boxed integers via RuntimeHelpers.Int32ToObject() instead of explicit boxing. This also touches MutableStringOps.cs TimeOps: - removed overloaded constructors to close bug #19956. But this exposes a new problem about Type aliasing that is described by bug 20035 (referencing a System::DateTime explicitly does not allow you to call the .NET constructors - only the Ruby-defined constructors). - fixed Time#- bug - #19955 ModuleOps: - fixed some very old bugs #15996, #15995 related to including non-sensible things (include 1, include nil). RequireNonClasses() method now throws the correct Ruby exceptions. This also touches SingletonOps.cs MutableStringOps: - added an implementation of String#rindex which closes #19904. We pass all specs except for 4 which fail because of differences between .NET regex and Ruby regex. Dir.cs: - cleaned up some code here, was about to work on glob implementation (bugs #19843 #19950, but handed off to Curt) FileOps.cs: - added an implementation of File#basename which closes #19905. passes all specs except for one which is wrong, and one which is unix-specific. These things are likely bugs in Ruby. #File.basename(''baz.rb'', ''z.rb'').should == ''ba'' -- bad test #File.basename("bar.txt.exe", ".txt.exe").should == "bar" - unix-only, should be wrapped in platform - added an implementation of File.file? to close #19949 MutableString.cs: - added a static Empty MutableString - added delegation thunks to LastIndexOf() - fixed our Equals() implementation to correctly distinguish between different types of strings (CLR vs. MutableString) File.cs: - fixes a bug related to what "w+" means in .NET. - its FileMode.OpenOrCreate Fixed bug #19885 by adding the -I command line switch which lets you specify the library load path. I''ve redefined our internal alias.txt file to generate aliases for rbd and rbx that include a pointer to where the MRI libs are stored in our layout. Fixed bug #17810, which was a long-standing perf bug. Fixed bug #20007, by allowing users to pass nothing for attr_accessor/reader/writer. This is really a bug in Ruby, but the current implementations allow this behavior, and there are apps that actually depend on it (RbYAML). Thanks, -John -------------- next part -------------- A non-text attachment was scrubbed... Name: merge-3.diff Type: application/octet-stream Size: 355608 bytes Desc: merge-3.diff URL: <http://rubyforge.org/pipermail/ironruby-core/attachments/20080510/941ab20a/attachment-0001.obj>
Quick question, are these following assertions are correct? ??? should_raise(TypeError){ File.basename(1) } ??? should_raise(TypeError){ File.basename("bar.txt", 1) } ??? should_raise(TypeError){ File.basename(true) } I was expecting all the above three should be ArgumentError than TypeError, until unless, you expect it to be TypeError, when I run the changes I have made for the all the above three by default you get the following error>>> File.basename(1):0:in `Initialize##1'': wrong number or type of arguments for `basename'' (Argumen tError) let me know if you would like me to validate and force throw TypeError execption. Also, in the basename_spec the test setup has wrong parameter on File.open(@name, ''w+''), if I change it to ''w'', the test runs fine otherwise none of the test works. Thanks, ----- Original Message ---- From: John Lam (IRONRUBY) <jflam at microsoft.com> To: IronRuby External Code Reviewers <irbrev at microsoft.com> Cc: "ironruby-core at rubyforge.org" <ironruby-core at rubyforge.org> Sent: Saturday, May 10, 2008 3:16:08 AM Subject: [Ironruby-core] RubyForge bug fixes tfpt review /shelveset:merge-3;REDMOND\jflam Ruby only This shelveset fixes a number of open bugs on Rubyforge and adds some features that we need to get the latest rubinius specs running. MatchDataOps: -? ? ? we used to alias MatchData to System.Text.RegularExpressions.Match. However, to fully implement MatchData we need to also hold onto a reference to the original string that we matched against. A new MatchData type was created (MatchData.cs) which wraps the existing .NET Match object. This also touches MutableStringOps.cs, RubyOps.cs, RubyScope.cs, SpecialGlobalVariableInfo.cs -? ? ? finished implementing all methods. 16 out of 16 specs pass -? ? ? implemented to_a which closes bug #19903 RegexpOps: -? ? ? added ctor overload to close bug #19927 -? ? ? made some changes to return MatchData objects instead of Match objects -? ? ? made some changes to return boxed integers via RuntimeHelpers.Int32ToObject() instead of explicit boxing. This also touches MutableStringOps.cs TimeOps: -? ? ? removed overloaded constructors to close bug #19956. But this exposes a new problem about Type aliasing that is described by bug 20035 (referencing a System::DateTime explicitly does not allow you to call the .NET constructors - only the Ruby-defined constructors). -? ? ? fixed Time#- bug - #19955 ModuleOps: -? ? ? fixed some very old bugs #15996, #15995 related to including non-sensible things (include 1, include nil). RequireNonClasses() method now throws the correct Ruby exceptions. This also touches SingletonOps.cs MutableStringOps: -? ? ? added an implementation of String#rindex which closes #19904. We pass all specs except for 4 which fail because of differences between .NET regex and Ruby regex. Dir.cs: -? ? ? cleaned up some code here, was about to work on glob implementation (bugs #19843 #19950, but handed off to Curt) FileOps.cs: -? ? ? added an implementation of File#basename which closes #19905. passes all specs except for one which is wrong, and one which is unix-specific. These things are likely bugs in Ruby. ? ? #File.basename(''baz.rb'', ''z.rb'').should == ''ba'' -- bad test ? ? #File.basename("bar.txt.exe", ".txt.exe").should == "bar" - unix-only, should be wrapped in platform -? ? ? added an implementation of File.file? to close #19949 MutableString.cs: -? ? ? added a static Empty MutableString -? ? ? added delegation thunks to LastIndexOf() -? ? ? fixed our Equals() implementation to correctly distinguish between different types of strings (CLR vs. MutableString) File.cs: -? ? ? fixes a bug related to what "w+" means in .NET. - its FileMode.OpenOrCreate Fixed bug #19885 by adding the -I command line switch which lets you specify the library load path. I''ve redefined our internal alias.txt file to generate aliases for rbd and rbx that include a pointer to where the MRI libs are stored in our layout. Fixed bug #17810, which was a long-standing perf bug. Fixed bug #20007, by allowing users to pass nothing for attr_accessor/reader/writer. This is really a bug in Ruby, but the current implementations allow this behavior, and there are apps that actually depend on it (RbYAML). Thanks, -John -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/ironruby-core/attachments/20080510/0a060786/attachment.html>
Unnikrishnan Nair:> Quick question, are these following assertions are correct? > > should_raise(TypeError){ File.basename(1) } > should_raise(TypeError){ File.basename("bar.txt", 1) } > should_raise(TypeError){ File.basename(true) }Yes they are. You can easily verify this in MRI yourself. In first and third cases, it hits the overload that accepts a nullable object as the first parameter. The TypeError is raised via Protocols.CastToString(). In the second case, it also hits an overload that accepts a nullable object as its second parameter, which raises TypeError via Protocols.CastToString(). FYI, this is the implementation of #basename that I have in my shelveset. It passes all of the (valid) specs - there are some legitimate bugs in our old copy of the specs (I haven''t checked with the latest version of the rubinius specs - I''ll do that next week). I''m a bit worried about how I''m handling the special cases for Windows. [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] public static MutableString/*!*/ Basename(CodeContext/*!*/ context, object/*!*/ self, [NotNull]MutableString/*!*/ path, [NotNull]MutableString/*!*/ extensionFilter) { if (path.Length == 0) return path; MutableString trimmedPath = TrimTrailingSlashes(path); // Special cases of drive letters C:\\ or C:/ if (trimmedPath.Length == 2) if (Char.IsLetter(trimmedPath.GetChar(0)) && trimmedPath.GetChar(1) == '':'') return Kernel.FlowTaint(context, path, (path.Length > 2 ? MutableString.Create(path.GetChar(2).ToString()) : MutableString.Create(String.Empty))); string trimmedPathAsString = trimmedPath.ConvertToString(); if (trimmedPathAsString == "/") return trimmedPath; string filename = System.IO.Path.GetFileName(trimmedPath.ConvertToString()); // Handle UNC host names correctly string root = System.IO.Path.GetPathRoot(trimmedPath.ConvertToString()); if (extensionFilter.Length == 0) return trimmedPathAsString == root ? MutableString.Create(root) : MutableString.Create(filename); string fileExtension = System.IO.Path.GetExtension(filename); string basename = System.IO.Path.GetFileNameWithoutExtension(filename); string result = WildcardExtensionMatch(fileExtension, extensionFilter.ConvertToString()) ? basename : filename; return Kernel.FlowTaint(context, self, (result.Equals(root) ? MutableString.Create(root) : MutableString.Create(result))); } [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] public static MutableString/*!*/ Basename(CodeContext/*!*/ context, object/*!*/ self, [NotNull]MutableString/*!*/ path) { return Basename(context, self, path, MutableString.Empty); } [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] public static MutableString/*!*/ Basename(CodeContext/*!*/ context, object/*!*/ self, object path, object extension) { return Basename(context, self, Protocols.CastToString(context, path), Protocols.CastToString(context, extension)); } [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] public static MutableString/*!*/ Basename(CodeContext/*!*/ context, object/*!*/ self, object path) { return Basename(context, self, Protocols.CastToString(context, path)); }> Also, in the basename_spec the test setup has wrong parameter on > File.open(@name, ''w+''), if I change it to ''w'', the test runs fine > otherwise none of the test works.This is correct. There is a bug in how we map the semantics of ''w+'' to .NET IO. It''s fixed in my shelveset. Thanks, -John
Hi John, Here is my code that I have, this is the first method I attemepted since this is one of the interesting logic. I thought I post my code for you to review as well. This passed most of the test as well[ { returnString = path; } [ { } [ {RubyMethod("basename", RubyMethodAttributes.PublicSingleton)]publicstaticMutableStringBasename(CodeContext/*!*/context, object/*!*/self, [NotNull]MutableString/*!*/path)MutableString[] tokens = path.Split(@"\/".ToCharArray(), Int32.MaxValue, StringSplitOptions.RemoveEmptyEntries);MutableStringreturnString = (tokens.GetLength(0) > 0) ? tokens[tokens.GetLength(0) - 1] : path; if((tokens.GetLength(0) > 0) && (returnString.GetChar(returnString.Length - 1).Equals('':'')))returnreturnString;RubyMethod("basename", RubyMethodAttributes.PublicSingleton)]publicstaticMutableStringBasename(CodeContext/*!*/context, object/*!*/self, object/*!*/path)returnBasename(context, self, Protocols.CastToString(context, path));RubyMethod("basename", RubyMethodAttributes.PublicSingleton)]publicstaticMutableStringBasename(CodeContext/*!*/context, object/*!*/self, [NotNull]MutableString/*!*/path, [NotNull]MutableString/*!*/filter)MutableStringfilename = Basename(context, self, path);//Treat ? speciallyif(filter.IndexOf(''?'') >= 0)returnfilename;//Treat .* and exetions specially using regex{ filter.Clear(); filter.Append( }if(filter.Equals(MutableString.Create(".*")))@"(?x)(\.[^.]*$|$)");else{ filter.Append( } System.Text.RegularExpressions. filename.Replace(mat.Index, mat.Length, } [ { } Let me know what do you think? Yes, I found some problems with test spec as well, (bar.txt should be baz) Thanks."$");RubyRegexreg = newRubyRegex(filter, System.Text.RegularExpressions.RegexOptions.Singleline);Matchmat = reg.Match(filename);if(mat.Success)MutableString.Create(""));returnfilename;RubyMethod("basename", RubyMethodAttributes.PublicSingleton)]publicstaticMutableStringBasename(CodeContext/*!*/context, object/*!*/self, object/*!*/path, object/*!*/filter)returnBasename(context, self, Protocols.CastToString(context, path), Protocols.CastToString(context, filter)); ----- Original Message ---- From: John Lam (IRONRUBY) <jflam at microsoft.com> To: "ironruby-core at rubyforge.org" <ironruby-core at rubyforge.org> Sent: Saturday, May 10, 2008 3:25:16 PM Subject: Re: [Ironruby-core] RubyForge bug fixes Unnikrishnan Nair:> Quick question, are these following assertions are correct? > >? ? should_raise(TypeError){ File.basename(1) } >? ? should_raise(TypeError){ File.basename("bar.txt", 1) } >? ? should_raise(TypeError){ File.basename(true) }Yes they are. You can easily verify this in MRI yourself. In first and third cases, it hits the overload that accepts a nullable object as the first parameter. The TypeError is raised via Protocols.CastToString(). In the second case, it also hits an overload that accepts a nullable object as its second parameter, which raises TypeError via Protocols.CastToString(). FYI, this is the implementation of #basename that I have in my shelveset. It passes all of the (valid) specs - there are some legitimate bugs in our old copy of the specs (I haven''t checked with the latest version of the rubinius specs - I''ll do that next week). I''m a bit worried about how I''m handling the special cases for Windows. [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] public static MutableString/*!*/ Basename(CodeContext/*!*/ context, object/*!*/ self, [NotNull]MutableString/*!*/ path, [NotNull]MutableString/*!*/ extensionFilter) { ? ? if (path.Length == 0) ? ? ? ? return path; ? ? MutableString trimmedPath = TrimTrailingSlashes(path); ? ? // Special cases of drive letters C:\\ or C:/ ? ? if (trimmedPath.Length == 2) ? ? ? ? if (Char.IsLetter(trimmedPath.GetChar(0)) && trimmedPath.GetChar(1) == '':'') ? ? ? ? ? ? return Kernel.FlowTaint(context, path, (path.Length > 2 ? MutableString.Create(path.GetChar(2).ToString()) : MutableString.Create(String.Empty))); ? ? string trimmedPathAsString = trimmedPath.ConvertToString(); ? ? if (trimmedPathAsString == "/") ? ? ? ? return trimmedPath; ? ? string filename = System.IO.Path.GetFileName(trimmedPath.ConvertToString()); ? ? // Handle UNC host names correctly ? ? string root = System.IO.Path.GetPathRoot(trimmedPath.ConvertToString()); ? ? if (extensionFilter.Length == 0) ? ? ? ? return trimmedPathAsString == root ? MutableString.Create(root) : MutableString.Create(filename); ? ? string fileExtension = System.IO.Path.GetExtension(filename); ? ? string basename = System.IO.Path.GetFileNameWithoutExtension(filename); ? ? string result = WildcardExtensionMatch(fileExtension, extensionFilter.ConvertToString()) ? basename : filename; ? ? return Kernel.FlowTaint(context, self, (result.Equals(root) ? MutableString.Create(root) : MutableString.Create(result))); } [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] public static MutableString/*!*/ Basename(CodeContext/*!*/ context, object/*!*/ self, [NotNull]MutableString/*!*/ path) { ? ? return Basename(context, self, path, MutableString.Empty); } [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] public static MutableString/*!*/ Basename(CodeContext/*!*/ context, object/*!*/ self, object path, object extension) { ? ? return Basename(context, self, Protocols.CastToString(context, path), Protocols.CastToString(context, extension)); } [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] public static MutableString/*!*/ Basename(CodeContext/*!*/ context, object/*!*/ self, object path) { ? ? return Basename(context, self, Protocols.CastToString(context, path)); }> Also, in the basename_spec the test setup has wrong parameter on > File.open(@name, ''w+''), if I change it to ''w'', the test runs fine > otherwise none of the test works.This is correct. There is a bug in how we map the semantics of ''w+'' to .NET IO. It''s fixed in my shelveset. Thanks, -John _______________________________________________ Ironruby-core mailing list Ironruby-core at rubyforge.org http://rubyforge.org/mailman/listinfo/ironruby-core -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/ironruby-core/attachments/20080510/55c016fd/attachment.html>
Hi Unnikrishnan, Just a couple of points you might find useful: . A number of overloads have parameters like ..., object/*!*/ path, ... What you are saying to the Specsharp tool is that object should never be null. Is this what you want? Can you pass nil into the methods in MRI? If you can then you need to remove the /*!*/. If you can''t then you probably need to add [NotNull] attribute or handle the case where the parameter is null within you method. Since you usually pass the value into CastToString, which handles the null case then probably removing the /*!*/ is what is required. . In Public Singleton methods I believe you can guarantee that the self parameter that gets passed in is actually the class that owns the method and so you can type this parameter to RubyClass/*!*/ if you want. Since the class is not being used in these methods it is not important, but it can save you a cast in other methods. . In some of the overloads you are using the Ruby regex classes. Do you know if MRI uses these and if so do they call the methods on them directly or via the Ruby method invocation process? If the latter then you need to use Dynamic Invocation to call the methods in your overloads [so that if someone monkey patches the Regex classes the behaviour shows up in the File class]. I suspect this is not the case but worth writing an RSpec for to check. . It might be worth pulling the MutableString objects that you use for comparison out into static readonly variables so that you don''t have to keep instantiating them every call. Such as: private static readonly MutableString dotStar = MutableString.Create(".*"); and private static readonly MutableString empty = MutableString.CreateEmpty(); Hope that helps. Pete From: ironruby-core-bounces at rubyforge.org [mailto:ironruby-core-bounces at rubyforge.org] On Behalf Of Unnikrishnan Nair Sent: Saturday,10 May 10, 2008 22:59 To: ironruby-core at rubyforge.org Subject: Re: [Ironruby-core] RubyForge bug fixes Hi John, Here is my code that I have, this is the first method I attemepted since this is one of the interesting logic. I thought I post my code for you to review as well. This passed most of the test as well [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] public static MutableString Basename(CodeContext/*!*/ context, object/*!*/ self, [NotNull]MutableString/*!*/ path) { MutableString[] tokens = path.Split(@"\/".ToCharArray(), Int32.MaxValue, StringSplitOptions.RemoveEmptyEntries); MutableString returnString = (tokens.GetLength(0) > 0) ? tokens[tokens.GetLength(0) - 1] : path; if ((tokens.GetLength(0) > 0) && (returnString.GetChar(returnString.Length - 1).Equals('':''))) returnString = path; return returnString; } [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] public static MutableString Basename(CodeContext/*!*/ context, object/*!*/ self, object/*!*/ path) { return Basename(context, self, Protocols.CastToString(context, path)); } [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] public static MutableString Basename(CodeContext/*!*/ context, object/*!*/ self, [NotNull]MutableString/*!*/ path, [NotNull]MutableString/*!*/ filter) { MutableString filename = Basename(context, self, path); //Treat ? specially if (filter.IndexOf(''?'') >= 0) return filename; //Treat .* and exetions specially using regex if (filter.Equals(MutableString.Create(".*"))) { filter.Clear(); filter.Append(@"(?x)(\.[^.]*$|$)"); } else { filter.Append("$"); } RubyRegex reg = new RubyRegex(filter, System.Text.RegularExpressions.RegexOptions.Singleline); System.Text.RegularExpressions.Match mat = reg.Match(filename); if (mat.Success) filename.Replace(mat.Index, mat.Length, MutableString.Create("")); return filename; } [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] public static MutableString Basename(CodeContext/*!*/ context, object/*!*/ self, object/*!*/ path, object/*!*/ filter) { return Basename(context, self, Protocols.CastToString(context, path), Protocols.CastToString(context, filter)); } Let me know what do you think? Yes, I found some problems with test spec as well, (bar.txt should be baz) Thanks. ----- Original Message ---- From: John Lam (IRONRUBY) <jflam at microsoft.com> To: "ironruby-core at rubyforge.org" <ironruby-core at rubyforge.org> Sent: Saturday, May 10, 2008 3:25:16 PM Subject: Re: [Ironruby-core] RubyForge bug fixes Unnikrishnan Nair:> Quick question, are these following assertions are correct? > > should_raise(TypeError){ File.basename(1) } > should_raise(TypeError){ File.basename("bar.txt", 1) } > should_raise(TypeError){ File.basename(true) }Yes they are. You can easily verify this in MRI yourself. In first and third cases, it hits the overload that accepts a nullable object as the first parameter. The TypeError is raised via Protocols.CastToString(). In the second case, it also hits an overload that accepts a nullable object as its second parameter, which raises TypeError via Protocols.CastToString(). FYI, this is the implementation of #basename that I have in my shelveset. It passes all of the (valid) specs - there are some legitimate bugs in our old copy of the specs (I haven''t checked with the latest version of the rubinius specs - I''ll do that next week). I''m a bit worried about how I''m handling the special cases for Windows. [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] public static MutableString/*!*/ Basename(CodeContext/*!*/ context, object/*!*/ self, [NotNull]MutableString/*!*/ path, [NotNull]MutableString/*!*/ extensionFilter) { if (path.Length == 0) return path; MutableString trimmedPath = TrimTrailingSlashes(path); // Special cases of drive letters C:\\ or C:/ if (trimmedPath.Length == 2) if (Char.IsLetter(trimmedPath.GetChar(0)) && trimmedPath.GetChar(1) == '':'') return Kernel.FlowTaint(context, path, (path.Length > 2 ? MutableString.Create(path.GetChar(2).ToString()) : MutableString.Create(String.Empty))); string trimmedPathAsString = trimmedPath.ConvertToString(); if (trimmedPathAsString == "/") return trimmedPath; string filename = System.IO <http://system.io.path.ge/> .Path.GetFileName(trimmedPath.ConvertToString()); // Handle UNC host names correctly string root = System.IO <http://system.io.path.ge/> .Path.GetPathRoot(trimmedPath.ConvertToString()); if (extensionFilter.Length == 0) return trimmedPathAsString == root ? MutableString.Create(root) : MutableString.Create(filename); string fileExtension = System.IO <http://system.io.path.ge/> .Path.GetExtension(filename); string basename = System.IO <http://system.io.path.ge/> .Path.GetFileNameWithoutExtension(filename); string result = WildcardExtensionMatch(fileExtension, extensionFilter.ConvertToString()) ? basename : filename; return Kernel.FlowTaint(context, self, (result.Equals(root) ? MutableString.Create(root) : MutableString.Create(result))); } [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] public static MutableString/*!*/ Basename(CodeContext/*!*/ context, object/*!*/ self, [NotNull]MutableString/*!*/ path) { return Basename(context, self, path, MutableString.Empty); } [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] public static MutableString/*!*/ Basename(CodeContext/*!*/ context, object/*!*/ self, object path, object extension) { return Basename(context, self, Protocols.CastToString(context, path), Protocols.CastToString(context, extension)); } [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] public static MutableString/*!*/ Basename(CodeContext/*!*/ context, object/*!*/ self, object path) { return Basename(context, self, Protocols.CastToString(context, path)); }> Also, in the basename_spec the test setup has wrong parameter on > File.open(@name, ''w+''), if I change it to ''w'', the test runs fine > otherwise none of the test works.This is correct. There is a bug in how we map the semantics of ''w+'' to .NET IO. It''s fixed in my shelveset. Thanks, -John _______________________________________________ Ironruby-core mailing list Ironruby-core at rubyforge.org http://rubyforge.org/mailman/listinfo/ironruby-core -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/ironruby-core/attachments/20080511/dd377698/attachment-0001.html>
Hi Peter, Fantastic point, now that I am understanding the code, it makes perfect sense, I really appriciate the comments. Thanks. ----- Original Message ---- From: Peter Bacon Darwin <bacondarwin at googlemail.com> To: ironruby-core at rubyforge.org Sent: Sunday, May 11, 2008 7:14:48 AM Subject: Re: [Ironruby-core] RubyForge bug fixes Hi Unnikrishnan, Just a couple of points you might find useful: ????????? A number of overloads have parameters like ..., object/*!*/ path, ... What you are saying to the Specsharp tool is that object should never be null.? Is this what you want?? Can you pass nil into the methods in MRI?? If you can then you need to remove the /*!*/.? If you can?t then you probably need to add [NotNull] attribute or handle the case where the parameter is null within you method.? Since you usually pass the value into CastToString, which handles the null case then probably removing the /*!*/ is what is required. ????????? In Public Singleton methods I believe you can guarantee that the self parameter that gets passed in is actually the class that owns the method and so you can type this parameter to RubyClass/*!*/ if you want.? Since the class is not being used in these methods it is not important, but it can save you a cast in other methods. ????????? In some of the overloads you are using the Ruby regex classes.? Do you know if MRI uses these and if so do they call the methods on them directly or via the Ruby method invocation process?? If the latter then you need to use Dynamic Invocation to call the methods in your overloads [so that if someone monkey patches the Regex classes the behaviour shows up in the File class].? I suspect this is not the case but worth writing an RSpec for to check. ????????? It might be worth pulling the MutableString objects that you use for comparison out into static readonly variables so that you don?t have to keep instantiating them every call.? Such as: private static readonly MutableString dotStar = MutableString.Create(".*"); and private static readonly MutableString empty = MutableString.CreateEmpty(); Hope that helps. Pete ? From:ironruby-core-bounces at rubyforge.org [mailto:ironruby-core-bounces at rubyforge.org] On Behalf Of Unnikrishnan Nair Sent: Saturday,10 May 10, 2008 22:59 To: ironruby-core at rubyforge.org Subject: Re: [Ironruby-core] RubyForge bug fixes ? Hi John, ? Here is my code that I have, this is the first method I attemepted since this is one of the interesting logic. I thought I post my code for you to review as well. This passed most of the test as well ? [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] publicstatic MutableString Basename(CodeContext/*!*/ context, object/*!*/ self, [NotNull]MutableString/*!*/ path) { MutableString[] tokens = path.Split(@"\/".ToCharArray(), Int32.MaxValue, StringSplitOptions.RemoveEmptyEntries); MutableStringreturnString = (tokens.GetLength(0) > 0) ? tokens[tokens.GetLength(0) - 1] : path; if((tokens.GetLength(0) > 0) && (returnString.GetChar(returnString.Length - 1).Equals('':''))) returnString = path; returnreturnString; } [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] publicstatic MutableString Basename(CodeContext/*!*/ context, object/*!*/ self, object/*!*/ path) { returnBasename(context, self, Protocols.CastToString(context, path)); } [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] publicstatic MutableString Basename(CodeContext/*!*/ context, object/*!*/ self, [NotNull]MutableString/*!*/ path, [NotNull]MutableString/*!*/ filter) { MutableStringfilename = Basename(context, self, path); //Treat ? specially if(filter.IndexOf(''?'') >= 0) returnfilename; //Treat .* and exetions specially using regex if(filter.Equals(MutableString.Create(".*"))) { filter.Clear(); filter.Append(@"(?x)(\.[^.]*$|$)"); } else { filter.Append("$"); } RubyRegexreg = new RubyRegex(filter, System.Text.RegularExpressions.RegexOptions.Singleline); System.Text.RegularExpressions.Match mat = reg.Match(filename); if(mat.Success) filename.Replace(mat.Index, mat.Length, MutableString.Create("")); returnfilename; } [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] publicstatic MutableString Basename(CodeContext/*!*/ context, object/*!*/ self, object/*!*/ path, object/*!*/ filter) { returnBasename(context, self, Protocols.CastToString(context, path), Protocols.CastToString(context, filter)); } ? Let me know what do you think? Yes, I found some problems with test spec as well, (bar.txt should be baz) ? Thanks. ? ? ----- Original Message ---- From: John Lam (IRONRUBY) <jflam at microsoft.com> To: "ironruby-core at rubyforge.org" <ironruby-core at rubyforge.org> Sent: Saturday, May 10, 2008 3:25:16 PM Subject: Re: [Ironruby-core] RubyForge bug fixes Unnikrishnan Nair:> Quick question, are these following assertions are correct? > >? ? should_raise(TypeError){ File.basename(1) } >? ? should_raise(TypeError){ File.basename("bar.txt", 1) } >? ? should_raise(TypeError){ File.basename(true) }Yes they are. You can easily verify this in MRI yourself. In first and third cases, it hits the overload that accepts a nullable object as the first parameter. The TypeError is raised via Protocols.CastToString(). In the second case, it also hits an overload that accepts a nullable object as its second parameter, which raises TypeError via Protocols.CastToString(). FYI, this is the implementation of #basename that I have in my shelveset. It passes all of the (valid) specs - there are some legitimate bugs in our old copy of the specs (I haven''t checked with the latest version of the rubinius specs - I''ll do that next week). I''m a bit worried about how I''m handling the special cases for Windows. [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] public static MutableString/*!*/ Basename(CodeContext/*!*/ context, object/*!*/ self, [NotNull]MutableString/*!*/ path, [NotNull]MutableString/*!*/ extensionFilter) { ? ? if (path.Length == 0) ? ? ? ? return path; ? ? MutableString trimmedPath = TrimTrailingSlashes(path); ? ? // Special cases of drive letters C:\\ or C:/ ? ? if (trimmedPath.Length == 2) ? ? ? ? if (Char.IsLetter(trimmedPath.GetChar(0)) && trimmedPath.GetChar(1) == '':'') ? ? ? ? ? ? return Kernel.FlowTaint(context, path, (path.Length > 2 ? MutableString.Create(path.GetChar(2).ToString()) : MutableString.Create(String.Empty))); ? ? string trimmedPathAsString = trimmedPath.ConvertToString(); ? ? if (trimmedPathAsString == "/") ? ? ? ? return trimmedPath; ? ? string filename = System.IO.Path.GetFileName(trimmedPath.ConvertToString()); ? ? // Handle UNC host names correctly ? ? string root = System.IO.Path.GetPathRoot(trimmedPath.ConvertToString()); ? ? if (extensionFilter.Length == 0) ? ? ? ? return trimmedPathAsString == root ? MutableString.Create(root) : MutableString.Create(filename); ? ? string fileExtension = System.IO.Path.GetExtension(filename); ? ? string basename = System.IO.Path.GetFileNameWithoutExtension(filename); ? ? string result = WildcardExtensionMatch(fileExtension, extensionFilter.ConvertToString()) ? basename : filename; ? ? return Kernel.FlowTaint(context, self, (result.Equals(root) ? MutableString.Create(root) : MutableString.Create(result))); } [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] public static MutableString/*!*/ Basename(CodeContext/*!*/ context, object/*!*/ self, [NotNull]MutableString/*!*/ path) { ? ? return Basename(context, self, path, MutableString.Empty); } [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] public static MutableString/*!*/ Basename(CodeContext/*!*/ context, object/*!*/ self, object path, object extension) { ? ? return Basename(context, self, Protocols.CastToString(context, path), Protocols.CastToString(context, extension)); } [RubyMethod("basename", RubyMethodAttributes.PublicSingleton)] public static MutableString/*!*/ Basename(CodeContext/*!*/ context, object/*!*/ self, object path) { ? ? return Basename(context, self, Protocols.CastToString(context, path)); }> Also, in the basename_spec the test setup has wrong parameter on > File.open(@name, ''w+''), if I change it to ''w'', the test runs fine > otherwise none of the test works.This is correct. There is a bug in how we map the semantics of ''w+'' to .NET IO. It''s fixed in my shelveset. Thanks, -John _______________________________________________ Ironruby-core mailing list Ironruby-core at rubyforge.org http://rubyforge.org/mailman/listinfo/ironruby-core -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/ironruby-core/attachments/20080511/4f00722c/attachment-0001.html>