ActiveSupport 如何计算月度总和?

2024-05-07

我很高兴也很惊讶地发现 ActiveSupport 按照我想要的方式进行月度汇总。无论相关月份中有多少天,添加1.month对特定的Time将使您在该月的同一天着陆Time.

> Time.utc(2012,2,1)
=> Wed Feb 01 00:00:00 UTC 2012
> Time.utc(2012,2,1) + 1.month
=> Thu Mar 01 00:00:00 UTC 2012

the months中的方法Fixnumactivesupport 提供的没有给出线索:

def months
  ActiveSupport::Duration.new(self * 30.days, [[:months, self]])
end

+中的方法Time...

def plus_with_duration(other) #:nodoc:
  if ActiveSupport::Duration === other
    other.since(self)
  else
    plus_without_duration(other)
  end
end

...引导我们since in Fixnum...

def since(time = ::Time.current)
  time + self
end

...这使我们无处可去。

ActiveSupport(或其他东西)如何/在哪里进行巧妙的月份计算,而不是仅仅添加 30 天?


这是一个非常好的问题。简短的回答是1.month is an ActiveSupport::Duration对象(正如您已经看到的)及其标识以两种不同的方式定义:

  • as 30.days(如果您需要/尝试将其转换为秒数),and
  • 为 1 个月(如果您尝试将此持续时间添加到日期中)。

你可以看到,通过检查它的值,它仍然知道它相当于 1 个月。parts method:

main > 1.month.parts
=> [[:months, 1]]

一旦你看到它仍然知道现在正好是 1 个月的证据,计算结果就不那么神秘了Time.utc(2012,2,1) + 1.month即使对于没有 29 天的月份也能给出正确的结果,以及为什么它给出的结果与Time.utc(2012,2,1) + 30.days gives.

How do ActiveSupport::Duration隐藏自己的真实身份?

对我来说,真正的谜团是它如何隐藏其真实身份如此之好。我们know它是一个ActiveSupport::Duration对象,但很难得到它admit这是!

当你在控制台中检查它时(我正在使用 Pry),它看起来完全像(并且声称be) 一个普通的 Fixnum 对象:

main > one_month = 1.month
=> 2592000

main > one_month.class
=> Fixnum

它甚至声称相当于30.days (or 2592000.seconds),我们已经证明这不是真的(至少不是在所有情况下):

main > one_month = 1.month
=> 2592000

main > thirty_days = 30.days
=> 2592000

main > one_month == thirty_days
=> true

main > one_month == 2592000
=> true

所以要找出一个对象是否是ActiveSupport::Duration无论是否,你都不能依赖class方法。相反,你必须直截了当地问它:“你是不是 ActiveSupport::Duration 的实例?”面对如此直接的问题,被质疑的对象将别无选择,只能坦白真相:

main > one_month.is_a? ActiveSupport::Duration
=> true

另一方面,纯粹的 Fixnum 对象必须低下头并承认它们不是:

main > 2592000.is_a? ActiveSupport::Duration
=> false

您还可以通过检查它是否响应来区分它与常规 Fixnums:parts:

main > one_month.parts
=> [[:months, 1]]

main > 2592000.parts
NoMethodError: undefined method `parts' for 2592000:Fixnum
from (pry):60:in `__pry__'

拥有一系列零件很棒

拥有一系列部件的一个很酷的事情是,它允许您将持续时间定义为单位的混合,如下所示:

main > (one_month + 5.days).parts
=> [[:months, 1], [:days, 5]]

这使得它能够准确计算以下内容:

main > Time.utc(2012,2,1) + (one_month + 5.days)
=> 2012-03-06 00:00:00 UTC

...它会not只要简单存储就能正确计算only一些days or seconds作为它的价值。如果我们首先转换,您可以亲自看到这一点1.month为其“等效”秒数或天数:

main > Time.utc(2012,2,1) + (one_month + 5.days).to_i
=> 2012-03-07 00:00:00 UTC

main > Time.utc(2012,2,1) + (30.days + 5.days)
=> 2012-03-07 00:00:00 UTC

如何ActiveSupport::Duration工作? (血淋淋的实施细节)

ActiveSupport::Duration实际上是定义的(在gems/activesupport-3.2.13/lib/active_support/duration.rb)作为子类BasicObject,根据docs http://www.ruby-doc.org/core-2.0/BasicObject.html,“可用于创建独立于 Ruby 对象层次结构的对象层次结构、代理对象(如 Delegator 类)或其他必须避免来自 Ruby 方法和类的命名空间污染的用途。”

ActiveSupport::Duration uses method_missing将方法委托给它@value多变的。

奖金问题: 有谁知道为什么ActiveSupport::Duration object claims不回应:parts尽管实际上does,为什么 parts 方法没有列在方法列表中?

main > 1.month.respond_to? :parts
=> false

main > 1.month.methods.include? :parts
=> false

main > 1.month.methods.include? :since
=> true

Answer: 因为BasicObject没有定义一个respond_to?方法,发送respond_to? to an ActiveSupport::Duration对象最终会调用它的method_missing方法,看起来像这样:

def method_missing(method, *args, &block) #:nodoc:
  value.send(method, *args, &block)
end

1.month.value只是 Fixnum2592000,所以它实际上最终调用2592000.respond_to? :parts,这当然是false.

不过,这很容易解决,只需添加一个respond_to?方法到ActiveSupport::Duration class:

main > ActiveSupport::Duration.class_eval do
           def respond_to?(name, include_private = false)
               [:value, :parts].include?(name) or
               value.respond_to?(name, include_private) or
               super
             end
         end
=> nil

main > 1.month.respond_to? :parts
=> true

原因的解释methods错误地省略了:parts方法是一样的:因为methods消息只是被委托给值,这当然是not have a parts方法。我们可以像添加我们自己的错误一样轻松地修复这个错误methods method:

main > ActiveSupport::Duration.class_eval do
         def methods(*args)
           [:value, :parts] | super
         end
       end
=> nil

main >  1.month.methods.include? :parts
=> true
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ActiveSupport 如何计算月度总和? 的相关文章

随机推荐

  • 文件嵌套时嵌入资源名称丢失扩展名

    我有一些脚本存储在我标记为嵌入式资源的文件中 我将每个文件嵌套在其关联的下面 cs文件 不幸的是 由于某种原因 当您以这种方式嵌套文件时 嵌入的资源名称会丢失文件扩展名 这意味着在运行时我无法识别哪些嵌入式资源是脚本 哪些不是脚本 对此我能
  • Pandas dataframe ,使用 iloc 替换最后一行

    我正在尝试使用 iloc 替换 Pandas 数据帧的最后一行 但是我无法让它工作 有很多解决方案 但最简单 最慢 的是这里 如何在 Python 中对 Pandas 数据帧上的行进行 FIFO 推送操作 https stackoverfl
  • 如何使用 Python 从 Azure Functions 中的辅助线程重定向日志

    我正在使用 Azure 函数运行启动多个线程的 Python 脚本 出于性能原因 一切都按预期工作 但 Azure Functions 日志中仅显示来自 main 线程的信息日志 我在 main 中启动的 辅助 线程中使用的所有日志都不会出
  • JavaFX 3D 面孔着色...再次

    我研究了这个question https stackoverflow com questions 26831871 coloring individual triangles in a triangle mesh on javafx 但我还
  • 如何使用pdfbox获取字体大小

    有谁知道 TextPosition 中的 getFontSize 方法是否总是返回 1 我应该只使用 getFontSizeInPt 来获取字体的大小吗 我遇到的问题是 getFontSizeInPt 有时会为相同大小的文本返回不同的值 对
  • 获取 Prometheus 中两个自定义时间戳之间的增量

    我有一个名为的普罗米修斯指标device number 我想要的是显示现在与一天 一周 一个月等之前的价值差异 这意味着减去具有两个不同时间戳的两个值 环顾四周 我没有找到任何关于如何执行此操作的有用文档 我想做但不起作用的是 sum de
  • JFreeChart奇怪的渲染(无头RedHat)

    我目前正在将一个应用程序从 Windows 环境迁移到 Redhat 环境 该应用程序使用 JfreeChart 1 0 6 它是部署在运行 Open JDK6 的 Redhat 无头环境中的 tomcat 7 中的 Web 应用程序 我得
  • 使用 WordPress 中的钩子在帖子更新(自定义帖子类型)后获取更新值

    我想获得更新后操作的最新更新值 我已经使用了 save post post updated publish post挂钩但全部返回旧值 但我同时需要当前更新值 我试过下面的代码 add action post updated wpse634
  • Materialize CSS,显示自动完成芯片的图像

    文档物化芯片 http materializecss com chips html展示您可以用图像制作芯片 div class chip img src images yuna jpg alt Contact Person Jane Doe
  • 如何添加到 OrientDB 中的空间索引?

    我正在使用工作室的 OrientDB 2 0 我使用文档中的代码成功创建了 Lucene 空间索引 CREATE class Place extends V CREATE property Place name string CREATE
  • 更改列名称的字母大小写

    我有大量数据集 每个数据集都包含一长串列名 在某些文件中 列名称全部大写 而在某些文件中 仅列名称的第一个字母大写 我需要附加数据集 并认为匹配数据集中的列名称的最简单方法是将全大写名称转换为仅第一个字母大写的名称 我希望找到一个通用的解决
  • 如何从symfony2中的现有表生成实体?

    我有带有一些字段的表 my table 我想在 MyBundle 中使用 my table 生成实体 但我不想重新创建 MyBundle 中的所有实体 我怎样才能做到这一点 这是你可以做到的方法 第一步 要求Doctrine自省数据库并生成
  • npm install 冻结并显示 IdealTree:chatting: sill IdealTree buildDeps

    当我安装任何东西时 npm 冻结了 即使删除 package lock json 也没有任何变化 这里有一个类似的问题 https stackoverflow com questions 50522376 npm install hangs
  • 如何以编程方式获取 Android 项目(非设备)中支持的语言列表

    在一些项目中我们可能会出现这种情况 如何以编程方式获取此应用程序 项目支持的语言列表 结果我需要这样的字符串数组 en bg bs da de hr it nl pl pt sk sr tr 当然 我可以通过键入它来对其进行硬编码 但我认为
  • 在 Bootstrap 导航栏后添加一些空间的最佳方法是什么?

    以下代码始终在页面顶部显示导航栏 我需要将第二个容器 内容 放置在导航栏的末尾而不是其下方 目前第二个容器位于导航栏下方 我可以在内容顶部添加一些空白 但我不确定这是一个好方法 知道如何解决吗 div class container div
  • 将 CSS 类应用于 asp:Hyperlink 中的图像?

    我使用 asp Hyperlink 根据 URL 中的参数动态呈现链接图像 我需要能够将 CSS 类添加到渲染的 img 中 但不知道如何做到这一点 我知道我可以将 CssClass blah 添加到asp Hyperlink 但在渲染的H
  • CSS3 过渡卡住了

    我们的新网站上正在进行很多转换 有一个特别之前工作得很好 但自从添加谷歌地图后 某种过渡效果不会触发 此外 它还会禁用网站上的所有其他过渡效果 直到触发另一个 javascript 函数 我不知道为什么 但这些就是事实 该问题似乎仅限于 S
  • 我的 QSqlQueryModel 不在列表视图中显示数据

    我正在玩 QSqlQueryModel 但我现在完全陷入困境 我一整天都在寻找解决方案 但到目前为止还没有运气 我所做的工作是它从我的 sqlite 数据库中提取数据 但由于某种原因我无法在列表视图中显示它 我的角色名似乎不存在 对于我从数
  • Typescript 1.8 模块:从文件夹导入所有文件

    我正在使用 Typescript 构建一个大型库 其中包含 100 个独立的 ts 文件 以前我用过导出模块XXX 重命名为导出命名空间 XXX稍后 对于我的所有课程 但正如书籍所说 这不是推荐的方法 我应该使用 import 代替 所以我
  • ActiveSupport 如何计算月度总和?

    我很高兴也很惊讶地发现 ActiveSupport 按照我想要的方式进行月度汇总 无论相关月份中有多少天 添加1 month对特定的Time将使您在该月的同一天着陆Time gt Time utc 2012 2 1 gt Wed Feb 0