Daniele Alessandri
2009-Aug-23 13:15 UTC
[Ironruby-core] Core Review: Time and IO#open fixes
Hi, here are some fixes for bugs I encountered while testing Ruote (http://github.com/jmettraux/ruote/) with IronRuby. As a side note, Ruote and its test suite depend on about 13 external libraries, and the fact that the number of failing tests is pretty much similar as if the suite was executed under MRI 1.8.6 on Windows is impressive to me. There is still a bunch of issues though, I will write a report later this week. * http://github.com/nrk/ironruby/commit/48a4a02b5b47d61f2f7a3f3887ea4bf02d63edb4 Miscellaneous fixes to Time: o The local time in Time.at must be computed on the result of the addition of seconds to the UTC value of epoch o Wrong bitmask in TimeOps.Load(RubyContext,object,MutableString) used to extract minutes and seconds from the binary data representing a ruby-marshalled instance of DateTime. o Time.local/Time.utc: . Added support for string and float arguments . The month argument is parsed as a number or a three-letter English name when it is string. . Added overloads to accepts 10 int/float arguments (C-style gmtime values, Time#to_a) * http://github.com/nrk/ironruby/commit/87d97c2cea0d917d72c5cd513b793bea3a502d3f Fixed a NullReferenceException in RubyIOOps.Open() raised when IO#open receives nil as the block parameter. irb(main):001:0> File.open("test.txt", &(nil)) => #<File:test.txt> irb(main):002:0> File.open("test.txt", &(Proc.new { |f| puts f.path })) test.txt => nil See the attached diff. -- Daniele Alessandri http://www.clorophilla.net/blog/ http://twitter.com/JoL1hAHN -------------- next part -------------- diff --git a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/time/local_tags.txt b/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/time/local_tags.txt index 3ad8a21..22df910 100644 --- a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/time/local_tags.txt +++ b/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/time/local_tags.txt @@ -1,8 +1,4 @@ fails:Time.local creates a time based on given values, interpreted in the local time zone fails:Time.local creates a time based on given C-style gmtime arguments, interpreted in the local time zone -fails:Time.local handles string-like second argument -fails:Time.local handles string arguments -fails:Time.local handles float arguments fails:Time.local should accept various year ranges fails:Time.local throws ArgumentError for out of range values -fails:Time.local throws ArgumentError for invalid number of arguments diff --git a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/time/utc_tags.txt b/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/time/utc_tags.txt index e8e7bdd..c6fa1a0 100644 --- a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/time/utc_tags.txt +++ b/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/time/utc_tags.txt @@ -1,9 +1,5 @@ fails:Time.utc creates a time based on given values, interpreted as UTC (GMT) fails:Time.utc creates a time based on given C-style gmtime arguments, interpreted as UTC (GMT) -fails:Time.utc handles string-like second argument -fails:Time.utc handles string arguments -fails:Time.utc handles float arguments fails:Time.utc should accept various year ranges fails:Time.utc throws ArgumentError for out of range values -fails:Time.utc throws ArgumentError for invalid number of arguments fails:Time#utc returns the utc representation of time diff --git a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/IoOps.cs b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/IoOps.cs index c10de39..0fcaae4 100644 --- a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/IoOps.cs +++ b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/IoOps.cs @@ -132,32 +132,31 @@ namespace IronRuby.Builtins { block.Yield(io, out result); io.Close(); return result; } } #region open [RubyMethod("open", RubyMethodAttributes.PublicSingleton)] public static RuleGenerator/*!*/ Open() { return new RuleGenerator((metaBuilder, args, name) => { var targetClass = (RubyClass)args.Target; targetClass.BuildObjectConstructionNoFlow(metaBuilder, args, name); // TODO: initialize yields the block? - // TODO: null block check - if (args.Signature.HasBlock) { + if (args.Signature.HasBlock && args.GetBlock() != null) { // ignore flow builder set up so far, we need one that creates a BlockParam for library calls: metaBuilder.ControlFlowBuilder = null; if (metaBuilder.BfcVariable == null) { metaBuilder.BfcVariable = metaBuilder.GetTemporary(typeof(BlockParam), "#bfc"); } metaBuilder.Result = Ast.Call(new Func<UnaryOpStorage, BlockParam, object, object>(InvokeOpenBlock).Method, Ast.Constant(new UnaryOpStorage(args.RubyContext)), metaBuilder.BfcVariable, metaBuilder.Result ); RubyMethodGroupInfo.RuleControlFlowBuilder(metaBuilder, args); } else { diff --git a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/TimeOps.cs b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/TimeOps.cs index 18e1d84..9075317 100644 --- a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/TimeOps.cs +++ b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/TimeOps.cs @@ -44,52 +44,129 @@ namespace IronRuby.Builtins { private static long microsecondsToTicks(long microseconds) { return microseconds * 10; } private static long secondsToTicks(long seconds) { return seconds * 10000000; } [RubyMethod("at", RubyMethodAttributes.PublicSingleton)] public static DateTime Create(object/*!*/ self, DateTime other) { return new DateTime(other.Ticks, other.Kind); } [RubyMethod("at", RubyMethodAttributes.PublicSingleton)] public static DateTime Create(object/*!*/ self, double seconds) { - return epoch.ToLocalTime().AddSeconds(seconds); + return epoch.AddSeconds(seconds).ToLocalTime(); } [RubyMethod("at", RubyMethodAttributes.PublicSingleton)] public static DateTime Create(object/*!*/ self, long seconds, long microseconds) { - long ticks = epoch.ToLocalTime().Ticks + secondsToTicks(seconds) + microsecondsToTicks(microseconds); - return new DateTime(ticks); + long ticks = epoch.Ticks + secondsToTicks(seconds) + microsecondsToTicks(microseconds); + return new DateTime(ticks).ToLocalTime(); } #endregion [RubyMethod("now", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateTime(object/*!*/ self) { return DateTime.Now; } [RubyMethod("today", RubyMethodAttributes.PublicSingleton)] public static DateTime Today(object self) { return DateTime.Today; } + + #region helpers for local, mktime, utc, gmt + + private static int GetComponent(ConversionStorage<IntegerValue>/*!*/ conversionStorage, ConversionStorage<MutableString>/*!*/ stringCast, + object[]/*!*/ components, int index, int defValue, bool isMonth) { + + if (index >= components.Length || components[index] == null) { + return defValue; + } + + if (components[index] is int) { + return (int)components[index]; + } + + if (components[index] is double) { + return (int)(double)components[index]; + } + + if (!isMonth) { + IntegerValue componentValue = components[index] is MutableString + ? Protocols.ConvertToInteger(conversionStorage, components[index]) + : Protocols.CastToInteger(conversionStorage, components[index]); + + return componentValue.Fixnum; + } + else { + // month is treated in a different way + + DateTime parsed; + MutableString month = components[index] is MutableString + ? components[index] as MutableString + : Protocols.CastToString(stringCast, components[index]); + + if (DateTime.TryParseExact(month.ToString(), "%M", CultureInfo.InvariantCulture, DateTimeStyles.None, out parsed)) { + return parsed.Month; + } + if (DateTime.TryParseExact(month.ToString(), "MMM", CultureInfo.InvariantCulture, DateTimeStyles.None, out parsed)) { + return parsed.Month; + } + + throw RubyExceptions.CreateArgumentError("argument out of range"); + } + } + + private static DateTime CreateTime(ConversionStorage<IntegerValue>/*!*/ conversionStorage, ConversionStorage<MutableString>/*!*/ stringCast, + object/*!*/ self, DateTimeKind kind, object[]/*!*/ components) { + + if (components.Length == 10) { + return new DateTime( + GetComponent(conversionStorage, stringCast, components, 5, 0, false), + GetComponent(conversionStorage, stringCast, components, 4, 0, true), + GetComponent(conversionStorage, stringCast, components, 3, 0, false), + GetComponent(conversionStorage, stringCast, components, 2, 1, false), + GetComponent(conversionStorage, stringCast, components, 1, 1, false), + GetComponent(conversionStorage, stringCast, components, 0, 0, false), + kind + ); + } + else { + if (components.Length > 7 || components.Length == 0) { + throw RubyExceptions.CreateArgumentError(String.Format("wrong number of arguments ({0} for 7)", components.Length)); + } + + return new DateTime( + GetComponent(conversionStorage, stringCast, components, 0, 0, false), + GetComponent(conversionStorage, stringCast, components, 1, 1, true), + GetComponent(conversionStorage, stringCast, components, 2, 1, false), + GetComponent(conversionStorage, stringCast, components, 3, 0, false), + GetComponent(conversionStorage, stringCast, components, 4, 0, false), + GetComponent(conversionStorage, stringCast, components, 5, 0, false), kind).AddTicks( + GetComponent(conversionStorage, stringCast, components, 6, 0, false) * 10 + ); + } + } + + #endregion + #region local, mktime [RubyMethod("local", RubyMethodAttributes.PublicSingleton)] [RubyMethod("mktime", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateLocalTime(object/*!*/ self, int year) { return new DateTime(year, 1, 1); } [RubyMethod("local", RubyMethodAttributes.PublicSingleton)] [RubyMethod("mktime", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateLocalTime(object/*!*/ self, int year, int month) { return new DateTime(year, month, 1); } [RubyMethod("local", RubyMethodAttributes.PublicSingleton)] @@ -107,56 +184,57 @@ namespace IronRuby.Builtins { [RubyMethod("local", RubyMethodAttributes.PublicSingleton)] [RubyMethod("mktime", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateLocalTime(object/*!*/ self, int year, int month, int day, int hour, int minute) { return new DateTime(year, month, day, hour, minute, 0); } [RubyMethod("local", RubyMethodAttributes.PublicSingleton)] [RubyMethod("mktime", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateLocalTime(object/*!*/ self, int year, int month, int day, int hour, int minute, int second) { return new DateTime(year, month, day, hour, minute, second); } [RubyMethod("local", RubyMethodAttributes.PublicSingleton)] [RubyMethod("mktime", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateLocalTime(object/*!*/ self, int year, int month, int day, int hour, int minute, int second, int microsecond) { - return new DateTime(year, month, day, hour, minute, second).AddTicks(microsecond*10); + return new DateTime(year, month, day, hour, minute, second).AddTicks(microsecond * 10); } - private static int GetComponent(ConversionStorage<int>/*!*/ conversionStorage, object[] components, int index, int defValue) { - if (index >= components.Length || components[index] == null) { - return defValue; - } - return Protocols.CastToFixnum(conversionStorage, components[index]); + [RubyMethod("local", RubyMethodAttributes.PublicSingleton)] + [RubyMethod("mktime", RubyMethodAttributes.PublicSingleton)] + public static DateTime CreateLocalTime(object/*!*/ self, int second, int minute, int hour, int day, int month, int year, + object wday, object yday, object isdst, object zone) { + + // wday, yday, isdst and zone are ignored + return new DateTime(year, month, day, hour, minute, second); } [RubyMethod("local", RubyMethodAttributes.PublicSingleton)] [RubyMethod("mktime", RubyMethodAttributes.PublicSingleton)] - public static DateTime CreateLocalTime(ConversionStorage<int>/*!*/ conversionStorage, object/*!*/ self, [NotNull]params object[]/*!*/ components) { + public static DateTime CreateLocalTime(object/*!*/ self, double second, double minute, double hour, double day, double month, double year, + object wday, object yday, object isdst, object zone) { - if (components.Length > 7 || components.Length == 0) { - throw RubyExceptions.CreateArgumentError(String.Format("wrong number of arguments ({0} for 7)", components.Length)); - } - - return new DateTime(Protocols.CastToFixnum(conversionStorage, components[0]), - GetComponent(conversionStorage, components, 1, 1), - GetComponent(conversionStorage, components, 2, 1), - GetComponent(conversionStorage, components, 3, 0), - GetComponent(conversionStorage, components, 4, 0), - GetComponent(conversionStorage, components, 5, 0), - GetComponent(conversionStorage, components, 6, 0) - ); + // wday, yday, isdst and zone are ignored + return new DateTime((int)year, (int)month, (int)day, (int)hour, (int)minute, (int)second); + } + + [RubyMethod("local", RubyMethodAttributes.PublicSingleton)] + [RubyMethod("mktime", RubyMethodAttributes.PublicSingleton)] + public static DateTime CreateLocalTime(ConversionStorage<IntegerValue>/*!*/ conversionStorage, ConversionStorage<MutableString>/*!*/ stringCast, + object/*!*/ self, [NotNull]params object[]/*!*/ components) { + + return CreateTime(conversionStorage, stringCast, self, DateTimeKind.Local, components); } #endregion #region utc, gm [RubyMethod("utc", RubyMethodAttributes.PublicSingleton)] [RubyMethod("gm", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateGmtTime(object/*!*/ self, int year) { return new DateTime(year, 1, 1, 0, 0, 0, DateTimeKind.Utc); } [RubyMethod("utc", RubyMethodAttributes.PublicSingleton)] [RubyMethod("gm", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateGmtTime(object/*!*/ self, int year, int month) { @@ -183,45 +261,52 @@ namespace IronRuby.Builtins { [RubyMethod("utc", RubyMethodAttributes.PublicSingleton)] [RubyMethod("gm", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateGmtTime(object/*!*/ self, int year, int month, int day, int hour, int minute, int second) { return new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc); } [RubyMethod("utc", RubyMethodAttributes.PublicSingleton)] [RubyMethod("gm", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateGmtTime(object/*!*/ self, int year, int month, int day, int hour, int minute, int second, int microsecond) { return new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc).AddTicks(microsecond * 10); } [RubyMethod("utc", RubyMethodAttributes.PublicSingleton)] [RubyMethod("gm", RubyMethodAttributes.PublicSingleton)] - public static DateTime CreateGmtTime(ConversionStorage<int>/*!*/ conversionStorage, RubyContext/*!*/ context, object/*!*/ self, - [NotNull]params object[]/*!*/ components) { + public static DateTime CreateGmtTime(object/*!*/ self, int second, int minute, int hour, int day, int month, int year, + object wday, object yday, object isdst, object zone) { - if (components.Length > 7 || components.Length == 0) { - throw RubyExceptions.CreateArgumentError(String.Format("wrong number of arguments ({0} for 7)", components.Length)); - } - return new DateTime( - Protocols.CastToFixnum(conversionStorage, components[0]), - GetComponent(conversionStorage, components, 1, 1), - GetComponent(conversionStorage, components, 2, 1), - GetComponent(conversionStorage, components, 3, 0), - GetComponent(conversionStorage, components, 4, 0), - GetComponent(conversionStorage, components, 5, 0), DateTimeKind.Utc).AddTicks( - GetComponent(conversionStorage, components, 6, 0) * 10 - ); + // wday, yday, isdst and zone are ignored + return new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc); + } + + [RubyMethod("utc", RubyMethodAttributes.PublicSingleton)] + [RubyMethod("gm", RubyMethodAttributes.PublicSingleton)] + public static DateTime CreateGmtTime(object/*!*/ self, double second, double minute, double hour, double day, double month, double year, + object wday, object yday, object isdst, object zone) { + + // wday, yday, isdst and zone are ignored + return new DateTime((int)year, (int)month, (int)day, (int)hour, (int)minute, (int)second, DateTimeKind.Utc); + } + + [RubyMethod("utc", RubyMethodAttributes.PublicSingleton)] + [RubyMethod("gm", RubyMethodAttributes.PublicSingleton)] + public static DateTime CreateGmtTime(ConversionStorage<IntegerValue>/*!*/ conversionStorage, ConversionStorage<MutableString>/*!*/ stringCast, + object/*!*/ self, [NotNull]params object[]/*!*/ components) { + + return CreateTime(conversionStorage, stringCast, self, DateTimeKind.Utc, components); } #endregion #endregion "Singleton Methods" #region _dump, _load [RubyMethod("_dump")] public static MutableString/*!*/ Dump(RubyContext/*!*/ context, DateTime self, [Optional]int depth) { if (self.Year < 1900) { throw RubyExceptions.CreateTypeError("unable to marshal time"); } uint dword1 = 0x80000000; @@ -255,32 +340,32 @@ namespace IronRuby.Builtins { [RubyMethod("_load", RubyMethodAttributes.PublicSingleton)] public static DateTime Load(RubyContext/*!*/ context, object/*!*/ self, [NotNull]MutableString time) { byte[] data = time.ConvertToBytes(); if (data.Length != 8 || (data[3] & 0x80) != 0x80) { throw RubyExceptions.CreateTypeError("marshaled time format differ"); } bool isUtc = (data[3] & 0x40) != 0; uint dword1 = GetUint(data, 0); int year = 1900 + (int)((dword1 >> 14) & 0xffff); int month = 1 + (int)((dword1 >> 10) & 0x0f); int day = (int)((dword1 >> 5) & 0x01f); int hour = (int)(dword1 & 0x01f); uint dword2 = GetUint(data, 4); - int minute = (int)((dword2 >> 26) & 0x2f); - int second = (int)((dword2 >> 20) & 0x2f); + int minute = (int)((dword2 >> 26) & 0x3f); + int second = (int)((dword2 >> 20) & 0x3f); int usec = (int)(dword2 & 0xfffff); try { DateTime result = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc); result = result.AddTicks(usec * 10L); if (!isUtc) { result = result.ToLocalTime(); } return result; } catch (ArgumentOutOfRangeException) { throw RubyExceptions.CreateTypeError("marshaled time format differ"); } } #endregion _dump, _load diff --git a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs index 25951a0..7052a2f 100644 --- a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs +++ b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs @@ -6052,72 +6052,80 @@ namespace IronRuby.Builtins { module.DefineLibraryMethod("at", 0x61, new System.Func<System.Object, System.DateTime, System.DateTime>(IronRuby.Builtins.TimeOps.Create), new System.Func<System.Object, System.Double, System.DateTime>(IronRuby.Builtins.TimeOps.Create), new System.Func<System.Object, System.Int64, System.Int64, System.DateTime>(IronRuby.Builtins.TimeOps.Create) ); module.DefineLibraryMethod("gm", 0x61, new System.Func<System.Object, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), - new System.Func<IronRuby.Runtime.ConversionStorage<System.Int32>, IronRuby.Runtime.RubyContext, System.Object, System.Object[], System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime) + new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Object, System.Object, System.Object, System.Object, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), + new System.Func<System.Object, System.Double, System.Double, System.Double, System.Double, System.Double, System.Double, System.Object, System.Object, System.Object, System.Object, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), + new System.Func<IronRuby.Runtime.ConversionStorage<IronRuby.Runtime.IntegerValue>, IronRuby.Runtime.ConversionStorage<IronRuby.Builtins.MutableString>, System.Object, System.Object[], System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime) ); module.DefineLibraryMethod("local", 0x61, new System.Func<System.Object, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), - new System.Func<IronRuby.Runtime.ConversionStorage<System.Int32>, System.Object, System.Object[], System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime) + new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Object, System.Object, System.Object, System.Object, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), + new System.Func<System.Object, System.Double, System.Double, System.Double, System.Double, System.Double, System.Double, System.Object, System.Object, System.Object, System.Object, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), + new System.Func<IronRuby.Runtime.ConversionStorage<IronRuby.Runtime.IntegerValue>, IronRuby.Runtime.ConversionStorage<IronRuby.Builtins.MutableString>, System.Object, System.Object[], System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime) ); module.DefineLibraryMethod("mktime", 0x61, new System.Func<System.Object, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), - new System.Func<IronRuby.Runtime.ConversionStorage<System.Int32>, System.Object, System.Object[], System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime) + new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Object, System.Object, System.Object, System.Object, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), + new System.Func<System.Object, System.Double, System.Double, System.Double, System.Double, System.Double, System.Double, System.Object, System.Object, System.Object, System.Object, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), + new System.Func<IronRuby.Runtime.ConversionStorage<IronRuby.Runtime.IntegerValue>, IronRuby.Runtime.ConversionStorage<IronRuby.Builtins.MutableString>, System.Object, System.Object[], System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime) ); module.DefineLibraryMethod("now", 0x61, new System.Func<System.Object, System.DateTime>(IronRuby.Builtins.TimeOps.CreateTime) ); module.DefineLibraryMethod("today", 0x61, new System.Func<System.Object, System.DateTime>(IronRuby.Builtins.TimeOps.Today) ); module.DefineLibraryMethod("utc", 0x61, new System.Func<System.Object, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), - new System.Func<IronRuby.Runtime.ConversionStorage<System.Int32>, IronRuby.Runtime.RubyContext, System.Object, System.Object[], System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime) + new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Object, System.Object, System.Object, System.Object, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), + new System.Func<System.Object, System.Double, System.Double, System.Double, System.Double, System.Double, System.Double, System.Object, System.Object, System.Object, System.Object, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), + new System.Func<IronRuby.Runtime.ConversionStorage<IronRuby.Runtime.IntegerValue>, IronRuby.Runtime.ConversionStorage<IronRuby.Builtins.MutableString>, System.Object, System.Object[], System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime) ); } private static void LoadTrueClass_Instance(IronRuby.Builtins.RubyModule/*!*/ module) { module.DefineLibraryMethod("&", 0x51, new System.Func<System.Boolean, System.Object, System.Boolean>(IronRuby.Builtins.TrueClass.And), new System.Func<System.Boolean, System.Boolean, System.Boolean>(IronRuby.Builtins.TrueClass.And) ); module.DefineLibraryMethod("^", 0x51, new System.Func<System.Boolean, System.Object, System.Boolean>(IronRuby.Builtins.TrueClass.Xor), new System.Func<System.Boolean, System.Boolean, System.Boolean>(IronRuby.Builtins.TrueClass.Xor) );
Daniele Alessandri
2009-Aug-23 20:19 UTC
[Ironruby-core] Core Review: Time and IO#open fixes
On Sun, Aug 23, 2009 at 15:15, Daniele Alessandri<suppakilla at gmail.com> wrote: [...]> * http://github.com/nrk/ironruby/commit/48a4a02b5b47d61f2f7a3f3887ea4bf02d63edb4 > Miscellaneous fixes to Time:[...] Just noticed the wrong link :-/ Here is the correct one: http://github.com/nrk/ironruby/commit/fb55ffcfb7193eba537eb4aba98c3d55871006d6 -- Daniele Alessandri http://www.clorophilla.net/blog/ http://twitter.com/JoL1hAHN
The IO#open block fix is almost correct yet it should rather be fixed in the RuleControlFlowBuilder. Since "args.GetBlock() != null" is a dynamic condition (the call-site doesn''t statically encode the value of the block) a rule test also needs to be added for nullity of the block. Otherwise call-site caching would be broken. I''ll take a look at it. Tomas -----Original Message----- From: ironruby-core-bounces at rubyforge.org [mailto:ironruby-core-bounces at rubyforge.org] On Behalf Of Daniele Alessandri Sent: Sunday, August 23, 2009 6:16 AM To: ironruby-core at rubyforge.org Subject: [Ironruby-core] Core Review: Time and IO#open fixes Hi, here are some fixes for bugs I encountered while testing Ruote (http://github.com/jmettraux/ruote/) with IronRuby. As a side note, Ruote and its test suite depend on about 13 external libraries, and the fact that the number of failing tests is pretty much similar as if the suite was executed under MRI 1.8.6 on Windows is impressive to me. There is still a bunch of issues though, I will write a report later this week. * http://github.com/nrk/ironruby/commit/48a4a02b5b47d61f2f7a3f3887ea4bf02d63edb4 Miscellaneous fixes to Time: o The local time in Time.at must be computed on the result of the addition of seconds to the UTC value of epoch o Wrong bitmask in TimeOps.Load(RubyContext,object,MutableString) used to extract minutes and seconds from the binary data representing a ruby-marshalled instance of DateTime. o Time.local/Time.utc: . Added support for string and float arguments . The month argument is parsed as a number or a three-letter English name when it is string. . Added overloads to accepts 10 int/float arguments (C-style gmtime values, Time#to_a) * http://github.com/nrk/ironruby/commit/87d97c2cea0d917d72c5cd513b793bea3a502d3f Fixed a NullReferenceException in RubyIOOps.Open() raised when IO#open receives nil as the block parameter. irb(main):001:0> File.open("test.txt", &(nil)) => #<File:test.txt> irb(main):002:0> File.open("test.txt", &(Proc.new { |f| puts f.path })) test.txt => nil See the attached diff. -- Daniele Alessandri http://www.clorophilla.net/blog/ http://twitter.com/JoL1hAHN
What are overloads like this: ...(int second, int minute, int hour, int day, int month, int year, object wday, object yday, object isdst, object zone) good for? It seems that the parameters typed to object are not used. Also when you cast double to int it might overflow. What should happen if a big integer is passed in? This is also suspicious: public static DateTime Create(object/*!*/ self, long seconds, long microseconds) MRI actually uses a default protocol for Fixnum for the parameters: class C def respond_to? name puts name true end def to_int 123 end end Time.at(C.new, 1.2) #=> to_int Time.at(C.new, 1000000000) #=> to_int Tomas -----Original Message----- From: ironruby-core-bounces at rubyforge.org [mailto:ironruby-core-bounces at rubyforge.org] On Behalf Of Daniele Alessandri Sent: Sunday, August 23, 2009 1:20 PM To: ironruby-core at rubyforge.org Subject: Re: [Ironruby-core] Core Review: Time and IO#open fixes On Sun, Aug 23, 2009 at 15:15, Daniele Alessandri<suppakilla at gmail.com> wrote: [...]> * http://github.com/nrk/ironruby/commit/48a4a02b5b47d61f2f7a3f3887ea4bf02d63edb4 > Miscellaneous fixes to Time:[...] Just noticed the wrong link :-/ Here is the correct one: http://github.com/nrk/ironruby/commit/fb55ffcfb7193eba537eb4aba98c3d55871006d6 -- Daniele Alessandri http://www.clorophilla.net/blog/ http://twitter.com/JoL1hAHN _______________________________________________ Ironruby-core mailing list Ironruby-core at rubyforge.org http://rubyforge.org/mailman/listinfo/ironruby-core
Daniele Alessandri
2009-Aug-24 07:01 UTC
[Ironruby-core] Core Review: Time and IO#open fixes
The int,int,int,int,int,int,object,object,object,object overloads are there just to skip the (relative) complexity of CreateTime when you pass 10 arguments to local/utc and all the relevant arguments are integers, e.g. when you do Time.local(*Time.now.to_a). The last four arguments are typed as object just because in the MRI you can pass whatever you want, they are totally ignored anyways. As for the double variant... well yeah, it might be superfluous and I guess it would be rarely used, so I will remove it. By the way the cast double -> int cast is admittedly wrong, that scenario under the MRI throws a RangeError: irb(main):001:0> Time.local(0,0,0,24,8,1_000_000_000_000_000_000.0,nil,nil,nil,nil) RangeError: float 1e+018 out of range of integer from (irb):1:in `local'' from (irb):1 from :0 I was going to use RubyOps.ConvertDoubleToFixnum(double) for that one, but I noticed that when it catches an overflow the message for RangeError is a little bit different (Fixnum instead of integer) and I was wondering if this difference was intentional or what. But then, I blatantly forgot to check it out and ask on the list... :-) As for Create(object,long,long) I can fix it while I am at it, I just committed the same change introduced in Create(object,double) but had not investigated other issues. Thanks, Daniele On Sun, Aug 23, 2009 at 23:58, Tomas Matousek<Tomas.Matousek at microsoft.com> wrote:> What are overloads like this: > ...(int second, int minute, int hour, int day, int month, int year, ?object wday, object yday, object isdst, object zone) > good for? > > It seems that the parameters typed to object are not used. Also when you cast double to int it might overflow. What should happen if a big integer is passed in? > > This is also suspicious: > > public static DateTime Create(object/*!*/ self, long seconds, long microseconds) > > MRI actually uses a default protocol for Fixnum for the parameters: > > class C > ?def respond_to? name > ? ?puts name > ? ?true > ?end > > ?def to_int > ? 123 > ?end > end > > Time.at(C.new, 1.2) ? ? ? ? ? ? ? ? ?#=> to_int > Time.at(C.new, 1000000000) #=> to_int > > Tomas > > > -----Original Message----- > From: ironruby-core-bounces at rubyforge.org [mailto:ironruby-core-bounces at rubyforge.org] On Behalf Of Daniele Alessandri > Sent: Sunday, August 23, 2009 1:20 PM > To: ironruby-core at rubyforge.org > Subject: Re: [Ironruby-core] Core Review: Time and IO#open fixes > > On Sun, Aug 23, 2009 at 15:15, Daniele Alessandri<suppakilla at gmail.com> wrote: > > [...] >> * http://github.com/nrk/ironruby/commit/48a4a02b5b47d61f2f7a3f3887ea4bf02d63edb4 >> Miscellaneous fixes to Time: > [...] > > Just noticed the wrong link :-/ Here is the correct one: > http://github.com/nrk/ironruby/commit/fb55ffcfb7193eba537eb4aba98c3d55871006d6 > > -- > Daniele Alessandri > http://www.clorophilla.net/blog/ > http://twitter.com/JoL1hAHN > _______________________________________________ > Ironruby-core mailing list > Ironruby-core at rubyforge.org > http://rubyforge.org/mailman/listinfo/ironruby-core > > _______________________________________________ > Ironruby-core mailing list > Ironruby-core at rubyforge.org > http://rubyforge.org/mailman/listinfo/ironruby-core >-- Daniele Alessandri http://www.clorophilla.net/blog/ http://twitter.com/JoL1hAHN
Daniele Alessandri
2009-Aug-24 20:32 UTC
[Ironruby-core] Core Review: Time and IO#open fixes
Hi, with this commit I think that things are definitely better than before: http://github.com/nrk/ironruby/commit/e880c0cffa337bffa31ed317ca673f8be7dd5795 It also fixes Time to behave just like MRI under circumstances similar to the following ones: irb(main):001:0> Time.local(2009,12,31,23,59,60) => Fri Jan 01 00:00:00 +0100 2010 irb(main):002:0> Time.local(2009,9,31,23,59,60) => Fri Oct 02 00:00:00 +0200 2009 irb(main):003:0> Time.local(2009,0,0) ArgumentError: argument out of range from (irb):3:in `local'' from (irb):3 irb(main):004:0> Time.local(20009) ArgumentError: time out of range from (irb):4:in `local'' from (irb):4 The attached diff includes this commit and the previous one. Thanks, Daniele On Mon, Aug 24, 2009 at 09:01, Daniele Alessandri<suppakilla at gmail.com> wrote:> The int,int,int,int,int,int,object,object,object,object overloads are > there just to skip the (relative) complexity of CreateTime when you > pass 10 arguments to local/utc and all the relevant arguments are > integers, e.g. when you do Time.local(*Time.now.to_a). The last four > arguments are typed as object just because in the MRI you can pass > whatever you want, they are totally ignored anyways. As for the double > variant... well yeah, it might be superfluous and I guess it would be > rarely used, so I will remove it. > > By the way the cast double -> int cast is admittedly wrong, that > scenario under the MRI throws a RangeError: > > irb(main):001:0> > Time.local(0,0,0,24,8,1_000_000_000_000_000_000.0,nil,nil,nil,nil) > RangeError: float 1e+018 out of range of integer > ? ? ? ?from (irb):1:in `local'' > ? ? ? ?from (irb):1 > ? ? ? ?from :0 > > I was going to use RubyOps.ConvertDoubleToFixnum(double) for that one, > but I noticed that when it catches an overflow the message for > RangeError is a little bit different (Fixnum instead of integer) and I > was wondering if this difference was intentional or what. But then, I > blatantly forgot to check it out and ask on the list... :-) > > As for Create(object,long,long) I can fix it while I am at it, I just > committed the same change introduced in Create(object,double) but had > not investigated other issues. > > Thanks, > Daniele > > > On Sun, Aug 23, 2009 at 23:58, Tomas > Matousek<Tomas.Matousek at microsoft.com> wrote: >> What are overloads like this: >> ...(int second, int minute, int hour, int day, int month, int year, ?object wday, object yday, object isdst, object zone) >> good for? >> >> It seems that the parameters typed to object are not used. Also when you cast double to int it might overflow. What should happen if a big integer is passed in? >> >> This is also suspicious: >> >> public static DateTime Create(object/*!*/ self, long seconds, long microseconds) >> >> MRI actually uses a default protocol for Fixnum for the parameters: >> >> class C >> ?def respond_to? name >> ? ?puts name >> ? ?true >> ?end >> >> ?def to_int >> ? 123 >> ?end >> end >> >> Time.at(C.new, 1.2) ? ? ? ? ? ? ? ? ?#=> to_int >> Time.at(C.new, 1000000000) #=> to_int >> >> Tomas >> >> >> -----Original Message----- >> From: ironruby-core-bounces at rubyforge.org [mailto:ironruby-core-bounces at rubyforge.org] On Behalf Of Daniele Alessandri >> Sent: Sunday, August 23, 2009 1:20 PM >> To: ironruby-core at rubyforge.org >> Subject: Re: [Ironruby-core] Core Review: Time and IO#open fixes >> >> On Sun, Aug 23, 2009 at 15:15, Daniele Alessandri<suppakilla at gmail.com> wrote: >> >> [...] >>> * http://github.com/nrk/ironruby/commit/48a4a02b5b47d61f2f7a3f3887ea4bf02d63edb4 >>> Miscellaneous fixes to Time: >> [...] >> >> Just noticed the wrong link :-/ Here is the correct one: >> http://github.com/nrk/ironruby/commit/fb55ffcfb7193eba537eb4aba98c3d55871006d6 >> >> -- >> Daniele Alessandri >> http://www.clorophilla.net/blog/ >> http://twitter.com/JoL1hAHN >> _______________________________________________ >> Ironruby-core mailing list >> Ironruby-core at rubyforge.org >> http://rubyforge.org/mailman/listinfo/ironruby-core >> >> _______________________________________________ >> Ironruby-core mailing list >> Ironruby-core at rubyforge.org >> http://rubyforge.org/mailman/listinfo/ironruby-core >> > > > > -- > Daniele Alessandri > http://www.clorophilla.net/blog/ > http://twitter.com/JoL1hAHN >-- Daniele Alessandri http://www.clorophilla.net/blog/ http://twitter.com/JoL1hAHN -------------- next part -------------- diff --git a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/time/local_tags.txt b/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/time/local_tags.txt index 3ad8a21..22df910 100644 --- a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/time/local_tags.txt +++ b/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/time/local_tags.txt @@ -1,8 +1,4 @@ fails:Time.local creates a time based on given values, interpreted in the local time zone fails:Time.local creates a time based on given C-style gmtime arguments, interpreted in the local time zone -fails:Time.local handles string-like second argument -fails:Time.local handles string arguments -fails:Time.local handles float arguments fails:Time.local should accept various year ranges fails:Time.local throws ArgumentError for out of range values -fails:Time.local throws ArgumentError for invalid number of arguments diff --git a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/time/utc_tags.txt b/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/time/utc_tags.txt index e8e7bdd..c6fa1a0 100644 --- a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/time/utc_tags.txt +++ b/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/time/utc_tags.txt @@ -1,9 +1,5 @@ fails:Time.utc creates a time based on given values, interpreted as UTC (GMT) fails:Time.utc creates a time based on given C-style gmtime arguments, interpreted as UTC (GMT) -fails:Time.utc handles string-like second argument -fails:Time.utc handles string arguments -fails:Time.utc handles float arguments fails:Time.utc should accept various year ranges fails:Time.utc throws ArgumentError for out of range values -fails:Time.utc throws ArgumentError for invalid number of arguments fails:Time#utc returns the utc representation of time diff --git a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/TimeOps.cs b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/TimeOps.cs index 18e1d84..529cf04 100644 --- a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/TimeOps.cs +++ b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/TimeOps.cs @@ -27,201 +27,299 @@ namespace IronRuby.Builtins { [RubyClass("Time", Extends = typeof(DateTime), Inherits = typeof(Object)), Includes(typeof(Comparable))] public static class TimeOps { readonly static DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); //January 1, 1970 00:00 UTC [RubyConstructor] public static DateTime Create(RubyClass/*!*/ self) { return DateTime.Now; } // TODO: I removed all of the constructor overloads since Ruby doesn''t define any non-default constructors for Time. // In the future, however, we need to fix this problem per RubyForge bug #20035 #region "Singleton Methods" - #region at + #region at private static long microsecondsToTicks(long microseconds) { return microseconds * 10; } private static long secondsToTicks(long seconds) { return seconds * 10000000; } [RubyMethod("at", RubyMethodAttributes.PublicSingleton)] public static DateTime Create(object/*!*/ self, DateTime other) { return new DateTime(other.Ticks, other.Kind); } [RubyMethod("at", RubyMethodAttributes.PublicSingleton)] public static DateTime Create(object/*!*/ self, double seconds) { - return epoch.ToLocalTime().AddSeconds(seconds); + return epoch.AddSeconds(seconds).ToLocalTime(); } - + [RubyMethod("at", RubyMethodAttributes.PublicSingleton)] public static DateTime Create(object/*!*/ self, long seconds, long microseconds) { - long ticks = epoch.ToLocalTime().Ticks + secondsToTicks(seconds) + microsecondsToTicks(microseconds); - return new DateTime(ticks); + long ticks = epoch.Ticks + secondsToTicks(seconds) + microsecondsToTicks(microseconds); + return new DateTime(ticks).ToLocalTime(); } #endregion [RubyMethod("now", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateTime(object/*!*/ self) { return DateTime.Now; } [RubyMethod("today", RubyMethodAttributes.PublicSingleton)] public static DateTime Today(object self) { return DateTime.Today; } + + #region helpers for local, mktime, utc, gmt + + private static int GetComponent(ConversionStorage<IntegerValue>/*!*/ conversionStorage, ConversionStorage<MutableString>/*!*/ stringCast, + object[]/*!*/ components, int index, int defValue, bool isMonth) { + + if (index >= components.Length || components[index] == null) { + return defValue; + } + + if (components[index] is int) { + return (int)components[index]; + } + + if (components[index] is double) { + return RubyOps.ConvertDoubleToFixnum((double)components[index]); + } + + if (!isMonth) { + IntegerValue componentValue = components[index] is MutableString + ? Protocols.ConvertToInteger(conversionStorage, components[index]) + : Protocols.CastToInteger(conversionStorage, components[index]); + + if (!componentValue.IsFixnum) { + throw RubyExceptions.CreateArgumentError("argument out of range"); + } + + return componentValue.Fixnum; + } else { + // month is treated in a different way + + DateTime parsed; + MutableString month = components[index] is MutableString + ? components[index] as MutableString + : Protocols.CastToString(stringCast, components[index]); + + if (DateTime.TryParseExact(month.ToString(), "%M", CultureInfo.InvariantCulture, DateTimeStyles.None, out parsed)) { + return parsed.Month; + } + if (DateTime.TryParseExact(month.ToString(), "MMM", CultureInfo.InvariantCulture, DateTimeStyles.None, out parsed)) { + return parsed.Month; + } + + throw RubyExceptions.CreateArgumentError("argument out of range"); + } + } + + private static DateTime CreateTime(object/*!*/ self, int year, int month, int day, int hour, int minute, int second, int microsecond, DateTimeKind kind) { + if (month < 1 || month > 12) { + throw RubyExceptions.CreateArgumentError("argument out of range"); + } + + if (day < 1 || day > 31) { + throw RubyExceptions.CreateArgumentError("argument out of range"); + } + + if (hour < 0 || hour > 23) { + throw RubyExceptions.CreateArgumentError("argument out of range"); + } + + if (minute < 0 || minute > 59) { + throw RubyExceptions.CreateArgumentError("argument out of range"); + } + + if (second < 0 || second > 60) { + throw RubyExceptions.CreateArgumentError("argument out of range"); + } + + try { + return new DateTime(year, month, 1, hour, minute, 0, kind).AddDays(day - 1).AddSeconds(second).AddTicks(microsecond * 10); + } catch (ArgumentOutOfRangeException) { + throw RubyExceptions.CreateArgumentError("time out of range"); + } + } + + private static DateTime CreateTime(ConversionStorage<IntegerValue>/*!*/ conversionStorage, ConversionStorage<MutableString>/*!*/ stringCast, + object/*!*/ self, DateTimeKind kind, object[]/*!*/ components) { + + if (components.Length == 10) { + return CreateTime(self, + GetComponent(conversionStorage, stringCast, components, 5, 0, false), + GetComponent(conversionStorage, stringCast, components, 4, 0, true), + GetComponent(conversionStorage, stringCast, components, 3, 0, false), + GetComponent(conversionStorage, stringCast, components, 2, 1, false), + GetComponent(conversionStorage, stringCast, components, 1, 1, false), + GetComponent(conversionStorage, stringCast, components, 0, 0, false), + 0, kind + ); + } else { + if (components.Length > 7 || components.Length == 0) { + throw RubyExceptions.CreateArgumentError(String.Format("wrong number of arguments ({0} for 7)", components.Length)); + } + + return CreateTime(self, + GetComponent(conversionStorage, stringCast, components, 0, 0, false), + GetComponent(conversionStorage, stringCast, components, 1, 1, true), + GetComponent(conversionStorage, stringCast, components, 2, 1, false), + GetComponent(conversionStorage, stringCast, components, 3, 0, false), + GetComponent(conversionStorage, stringCast, components, 4, 0, false), + GetComponent(conversionStorage, stringCast, components, 5, 0, false), + GetComponent(conversionStorage, stringCast, components, 6, 0, false), + kind + ); + } + } + + #endregion + #region local, mktime [RubyMethod("local", RubyMethodAttributes.PublicSingleton)] [RubyMethod("mktime", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateLocalTime(object/*!*/ self, int year) { - return new DateTime(year, 1, 1); + return CreateTime(self, year, 1, 1, 0, 0, 0, 0, DateTimeKind.Local); } [RubyMethod("local", RubyMethodAttributes.PublicSingleton)] [RubyMethod("mktime", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateLocalTime(object/*!*/ self, int year, int month) { - return new DateTime(year, month, 1); + return CreateTime(self, year, month, 1, 0, 0, 0, 0, DateTimeKind.Local); } [RubyMethod("local", RubyMethodAttributes.PublicSingleton)] [RubyMethod("mktime", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateLocalTime(object/*!*/ self, int year, int month, int day) { - return new DateTime(year, month, day); + return CreateTime(self, year, month, day, 0, 0, 0, 0, DateTimeKind.Local); } [RubyMethod("local", RubyMethodAttributes.PublicSingleton)] [RubyMethod("mktime", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateLocalTime(object/*!*/ self, int year, int month, int day, int hour) { - return new DateTime(year, month, day, hour, 0, 0); + return CreateTime(self, year, month, day, hour, 0, 0, 0, DateTimeKind.Local); } [RubyMethod("local", RubyMethodAttributes.PublicSingleton)] [RubyMethod("mktime", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateLocalTime(object/*!*/ self, int year, int month, int day, int hour, int minute) { - return new DateTime(year, month, day, hour, minute, 0); + return CreateTime(self, year, month, day, hour, minute, 0, 0, DateTimeKind.Local); } [RubyMethod("local", RubyMethodAttributes.PublicSingleton)] [RubyMethod("mktime", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateLocalTime(object/*!*/ self, int year, int month, int day, int hour, int minute, int second) { - return new DateTime(year, month, day, hour, minute, second); + return CreateTime(self, year, month, day, hour, minute, second, 0, DateTimeKind.Local); } [RubyMethod("local", RubyMethodAttributes.PublicSingleton)] [RubyMethod("mktime", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateLocalTime(object/*!*/ self, int year, int month, int day, int hour, int minute, int second, int microsecond) { - return new DateTime(year, month, day, hour, minute, second).AddTicks(microsecond*10); + return CreateTime(self, year, month, day, hour, minute, second, microsecond, DateTimeKind.Local); } - private static int GetComponent(ConversionStorage<int>/*!*/ conversionStorage, object[] components, int index, int defValue) { - if (index >= components.Length || components[index] == null) { - return defValue; - } - return Protocols.CastToFixnum(conversionStorage, components[index]); + [RubyMethod("local", RubyMethodAttributes.PublicSingleton)] + [RubyMethod("mktime", RubyMethodAttributes.PublicSingleton)] + public static DateTime CreateLocalTime(object/*!*/ self, int second, int minute, int hour, int day, int month, int year, + object wday, object yday, object isdst, object zone) { + + // wday, yday, isdst and zone are ignored + return CreateTime(self, year, month, day, hour, minute, second, 0, DateTimeKind.Local); } [RubyMethod("local", RubyMethodAttributes.PublicSingleton)] [RubyMethod("mktime", RubyMethodAttributes.PublicSingleton)] - public static DateTime CreateLocalTime(ConversionStorage<int>/*!*/ conversionStorage, object/*!*/ self, [NotNull]params object[]/*!*/ components) { + public static DateTime CreateLocalTime(ConversionStorage<IntegerValue>/*!*/ conversionStorage, ConversionStorage<MutableString>/*!*/ stringCast, + object/*!*/ self, [NotNull]params object[]/*!*/ components) { - if (components.Length > 7 || components.Length == 0) { - throw RubyExceptions.CreateArgumentError(String.Format("wrong number of arguments ({0} for 7)", components.Length)); - } - - return new DateTime(Protocols.CastToFixnum(conversionStorage, components[0]), - GetComponent(conversionStorage, components, 1, 1), - GetComponent(conversionStorage, components, 2, 1), - GetComponent(conversionStorage, components, 3, 0), - GetComponent(conversionStorage, components, 4, 0), - GetComponent(conversionStorage, components, 5, 0), - GetComponent(conversionStorage, components, 6, 0) - ); + return CreateTime(conversionStorage, stringCast, self, DateTimeKind.Local, components); } #endregion #region utc, gm [RubyMethod("utc", RubyMethodAttributes.PublicSingleton)] [RubyMethod("gm", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateGmtTime(object/*!*/ self, int year) { - return new DateTime(year, 1, 1, 0, 0, 0, DateTimeKind.Utc); + return CreateTime(self, year, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); } [RubyMethod("utc", RubyMethodAttributes.PublicSingleton)] [RubyMethod("gm", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateGmtTime(object/*!*/ self, int year, int month) { - return new DateTime(year, month, 1, 0, 0, 0, DateTimeKind.Utc); + return CreateTime(self, year, month, 1, 0, 0, 0, 0, DateTimeKind.Utc); } [RubyMethod("utc", RubyMethodAttributes.PublicSingleton)] [RubyMethod("gm", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateGmtTime(object/*!*/ self, int year, int month, int day) { - return new DateTime(year, month, day, 0, 0, 0, DateTimeKind.Utc); + return CreateTime(self, year, month, day, 0, 0, 0, 0, DateTimeKind.Utc); } [RubyMethod("utc", RubyMethodAttributes.PublicSingleton)] [RubyMethod("gm", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateGmtTime(object/*!*/ self, int year, int month, int day, int hour) { - return new DateTime(year, month, day, hour, 0, 0, DateTimeKind.Utc); + return CreateTime(self, year, month, day, hour, 0, 0, 0, DateTimeKind.Utc); } [RubyMethod("utc", RubyMethodAttributes.PublicSingleton)] [RubyMethod("gm", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateGmtTime(object/*!*/ self, int year, int month, int day, int hour, int minute) { - return new DateTime(year, month, day, hour, minute, 0, DateTimeKind.Utc); + return CreateTime(self, year, month, day, hour, minute, 0, 0, DateTimeKind.Utc); } [RubyMethod("utc", RubyMethodAttributes.PublicSingleton)] [RubyMethod("gm", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateGmtTime(object/*!*/ self, int year, int month, int day, int hour, int minute, int second) { - return new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc); + return CreateTime(self, year, month, day, hour, minute, second, 0, DateTimeKind.Utc); } [RubyMethod("utc", RubyMethodAttributes.PublicSingleton)] [RubyMethod("gm", RubyMethodAttributes.PublicSingleton)] public static DateTime CreateGmtTime(object/*!*/ self, int year, int month, int day, int hour, int minute, int second, int microsecond) { - return new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc).AddTicks(microsecond * 10); + return CreateTime(self, year, month, day, hour, minute, second, microsecond, DateTimeKind.Utc); } [RubyMethod("utc", RubyMethodAttributes.PublicSingleton)] [RubyMethod("gm", RubyMethodAttributes.PublicSingleton)] - public static DateTime CreateGmtTime(ConversionStorage<int>/*!*/ conversionStorage, RubyContext/*!*/ context, object/*!*/ self, - [NotNull]params object[]/*!*/ components) { + public static DateTime CreateGmtTime(object/*!*/ self, int second, int minute, int hour, int day, int month, int year, + object wday, object yday, object isdst, object zone) { - if (components.Length > 7 || components.Length == 0) { - throw RubyExceptions.CreateArgumentError(String.Format("wrong number of arguments ({0} for 7)", components.Length)); - } - return new DateTime( - Protocols.CastToFixnum(conversionStorage, components[0]), - GetComponent(conversionStorage, components, 1, 1), - GetComponent(conversionStorage, components, 2, 1), - GetComponent(conversionStorage, components, 3, 0), - GetComponent(conversionStorage, components, 4, 0), - GetComponent(conversionStorage, components, 5, 0), DateTimeKind.Utc).AddTicks( - GetComponent(conversionStorage, components, 6, 0) * 10 - ); + // wday, yday, isdst and zone are ignored + return CreateTime(self, year, month, day, hour, minute, second, 0, DateTimeKind.Utc); + } + + [RubyMethod("utc", RubyMethodAttributes.PublicSingleton)] + [RubyMethod("gm", RubyMethodAttributes.PublicSingleton)] + public static DateTime CreateGmtTime(ConversionStorage<IntegerValue>/*!*/ conversionStorage, ConversionStorage<MutableString>/*!*/ stringCast, + object/*!*/ self, [NotNull]params object[]/*!*/ components) { + + return CreateTime(conversionStorage, stringCast, self, DateTimeKind.Utc, components); } #endregion #endregion "Singleton Methods" #region _dump, _load [RubyMethod("_dump")] public static MutableString/*!*/ Dump(RubyContext/*!*/ context, DateTime self, [Optional]int depth) { if (self.Year < 1900) { throw RubyExceptions.CreateTypeError("unable to marshal time"); } uint dword1 = 0x80000000; @@ -255,32 +353,32 @@ namespace IronRuby.Builtins { [RubyMethod("_load", RubyMethodAttributes.PublicSingleton)] public static DateTime Load(RubyContext/*!*/ context, object/*!*/ self, [NotNull]MutableString time) { byte[] data = time.ConvertToBytes(); if (data.Length != 8 || (data[3] & 0x80) != 0x80) { throw RubyExceptions.CreateTypeError("marshaled time format differ"); } bool isUtc = (data[3] & 0x40) != 0; uint dword1 = GetUint(data, 0); int year = 1900 + (int)((dword1 >> 14) & 0xffff); int month = 1 + (int)((dword1 >> 10) & 0x0f); int day = (int)((dword1 >> 5) & 0x01f); int hour = (int)(dword1 & 0x01f); uint dword2 = GetUint(data, 4); - int minute = (int)((dword2 >> 26) & 0x2f); - int second = (int)((dword2 >> 20) & 0x2f); + int minute = (int)((dword2 >> 26) & 0x3f); + int second = (int)((dword2 >> 20) & 0x3f); int usec = (int)(dword2 & 0xfffff); try { DateTime result = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc); result = result.AddTicks(usec * 10L); if (!isUtc) { result = result.ToLocalTime(); } return result; } catch (ArgumentOutOfRangeException) { throw RubyExceptions.CreateTypeError("marshaled time format differ"); } } #endregion _dump, _load @@ -554,31 +652,31 @@ namespace IronRuby.Builtins { [RubyMethod("to_a")] public static RubyArray ToArray(DateTime/*!*/ self) { RubyArray result = new RubyArray(); result.Add(self.Second); result.Add(self.Minute); result.Add(self.Hour); result.Add(self.Day); result.Add(self.Month); result.Add(self.Year); result.Add((int)self.DayOfWeek); result.Add(self.DayOfYear); result.Add(self.IsDaylightSavingTime()); result.Add(GetZone(self)); return result; - } + } [RubyMethod("wday")] public static int DayOfWeek(DateTime/*!*/ self) { return (int)self.DayOfWeek; } [RubyMethod("hash")] public static int GetHash(DateTime/*!*/ self) { return self.GetHashCode(); } [RubyMethod("zone")] public static MutableString/*!*/ GetZone(DateTime/*!*/ self) { // TODO: return MutableString.CreateAscii("UTC"); diff --git a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs index 25951a0..353626e 100644 --- a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs +++ b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs @@ -6052,72 +6052,76 @@ namespace IronRuby.Builtins { module.DefineLibraryMethod("at", 0x61, new System.Func<System.Object, System.DateTime, System.DateTime>(IronRuby.Builtins.TimeOps.Create), new System.Func<System.Object, System.Double, System.DateTime>(IronRuby.Builtins.TimeOps.Create), new System.Func<System.Object, System.Int64, System.Int64, System.DateTime>(IronRuby.Builtins.TimeOps.Create) ); module.DefineLibraryMethod("gm", 0x61, new System.Func<System.Object, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), - new System.Func<IronRuby.Runtime.ConversionStorage<System.Int32>, IronRuby.Runtime.RubyContext, System.Object, System.Object[], System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime) + new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Object, System.Object, System.Object, System.Object, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), + new System.Func<IronRuby.Runtime.ConversionStorage<IronRuby.Runtime.IntegerValue>, IronRuby.Runtime.ConversionStorage<IronRuby.Builtins.MutableString>, System.Object, System.Object[], System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime) ); module.DefineLibraryMethod("local", 0x61, new System.Func<System.Object, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), - new System.Func<IronRuby.Runtime.ConversionStorage<System.Int32>, System.Object, System.Object[], System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime) + new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Object, System.Object, System.Object, System.Object, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), + new System.Func<IronRuby.Runtime.ConversionStorage<IronRuby.Runtime.IntegerValue>, IronRuby.Runtime.ConversionStorage<IronRuby.Builtins.MutableString>, System.Object, System.Object[], System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime) ); module.DefineLibraryMethod("mktime", 0x61, new System.Func<System.Object, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), - new System.Func<IronRuby.Runtime.ConversionStorage<System.Int32>, System.Object, System.Object[], System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime) + new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Object, System.Object, System.Object, System.Object, System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime), + new System.Func<IronRuby.Runtime.ConversionStorage<IronRuby.Runtime.IntegerValue>, IronRuby.Runtime.ConversionStorage<IronRuby.Builtins.MutableString>, System.Object, System.Object[], System.DateTime>(IronRuby.Builtins.TimeOps.CreateLocalTime) ); module.DefineLibraryMethod("now", 0x61, new System.Func<System.Object, System.DateTime>(IronRuby.Builtins.TimeOps.CreateTime) ); module.DefineLibraryMethod("today", 0x61, new System.Func<System.Object, System.DateTime>(IronRuby.Builtins.TimeOps.Today) ); module.DefineLibraryMethod("utc", 0x61, new System.Func<System.Object, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), - new System.Func<IronRuby.Runtime.ConversionStorage<System.Int32>, IronRuby.Runtime.RubyContext, System.Object, System.Object[], System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime) + new System.Func<System.Object, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Object, System.Object, System.Object, System.Object, System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime), + new System.Func<IronRuby.Runtime.ConversionStorage<IronRuby.Runtime.IntegerValue>, IronRuby.Runtime.ConversionStorage<IronRuby.Builtins.MutableString>, System.Object, System.Object[], System.DateTime>(IronRuby.Builtins.TimeOps.CreateGmtTime) ); } private static void LoadTrueClass_Instance(IronRuby.Builtins.RubyModule/*!*/ module) { module.DefineLibraryMethod("&", 0x51, new System.Func<System.Boolean, System.Object, System.Boolean>(IronRuby.Builtins.TrueClass.And), new System.Func<System.Boolean, System.Boolean, System.Boolean>(IronRuby.Builtins.TrueClass.And) ); module.DefineLibraryMethod("^", 0x51, new System.Func<System.Boolean, System.Object, System.Boolean>(IronRuby.Builtins.TrueClass.Xor), new System.Func<System.Boolean, System.Boolean, System.Boolean>(IronRuby.Builtins.TrueClass.Xor) );