我正在为一个来自 Rails 的新项目学习 Scala。我已经定义了一个将在我的许多模型中使用的类型,它基本上可以被认为是“属性”的集合。它基本上只是一个 hashmap 的包装器,将其大部分职责委托(delegate)给它:
case class Description(attributes: Map[String, String]) {
override def hashCode: Int = attributes.hashCode
override def equals(other: Any) = other match {
case that: Description => this.attributes == that.attributes
case _ => false
}
}
然后我会用Description定义一个模型类,比如:
case class Person(val name: String, val description: Description)
但是,当我将 Person 与 SalatDAO 持久化时,我最终得到的文档如下所示:
{
name : "Russell",
description:
{
attributes:
{
hair: "brown",
favourite_color: "blue"
}
}
}
实际上我不需要在 description 标签中嵌套 attributes 标签——我真正想要的是:
{
name : "Russell",
description:
{
hair: "brown",
favourite_color: "blue"
}
}
我没试过,但我想如果我让 Description 扩展一个 Map 而不是包含一个,我想我可以让它工作,但我宁愿不,因为 Description 不是 Map 的一种,它具有 Map 的某些行为以及它自己的我稍后会添加。组合优于继承等等。
所以我的问题是,我如何告诉 Salat(或 Casbah,实际上我有点不清楚是哪个在进行转换,因为我才刚刚开始使用它们)如何序列化和反序列化 说明类?在casbah教程中here它说:
It is also possible to create your own custom type serializers and deserializers. See Custom Serializers and Deserializers.
但是这个页面好像不存在。还是我走错了路?实际上是否有一种非常简单的方法来表明这是我想要发生的事情,注释或其他什么?或者我可以简单地将序列化以某种方式委托(delegate)给属性映射吗?
编辑:在查看了 JodaTime 转换助手的源代码后,我尝试了以下方法,但还没有成功:
import org.bson.{ BSON, Transformer }
import com.mongodb.casbah.commons.conversions.MongoConversionHelper
object RegisterCustomConversionHelpers extends Serializers
with Deserializers {
def apply() = {
super.register()
}
}
trait Serializers extends MongoConversionHelper
with DescriptionSerializer {
override def register() = {
super.register()
}
override def unregister() = {
super.unregister()
}
}
trait Deserializers extends MongoConversionHelper {
override def register() = {
super.register()
}
override def unregister() = {
super.unregister()
}
}
trait DescriptionSerializer extends MongoConversionHelper {
private val transformer = new Transformer {
def transform(o: AnyRef): AnyRef = o match {
case d: Description => d.attributes.asInstanceOf[AnyRef]
case _ => o
}
}
override def register() = {
BSON.addEncodingHook(classOf[Description], transformer)
super.register()
}
}
当我调用 RegisterCustomConversionHelpers() 然后保存一个 Person 时,我没有收到任何错误,它只是没有效果,保存文档的方式与以往相同。为了我想要的,这似乎还有很多事情要做。
最佳答案
Salat 维护者在这里。
我不明白 Description 在这里作为包装器的值(value)。它包装了一个属性映射,覆盖了一个 case 类的默认 equals 和 hashcode impl——这似乎是不必要的,因为无论如何 impl 被委托(delegate)给了映射,而这正是 case 类所做的——并引入了一个额外的间接层序列化对象。
您是否考虑过:
case class Person(val name: String, val description: Map[String, String])
这将完全满足您的需求。
在另一种情况下,我会推荐一个简单的类型别名,但不幸的是,Salat 目前无法支持类型别名,因为它们在 pickled Scala 签名中的描述方式存在一些问题。
(您可能出于简洁的考虑从您的示例中省略了这一点,但是您的 Mongo 模型最好有一个 _id 字段 - 如果您没有,Mongo Java 驱动程序将为您提供一个)
salat-core 测试包中有一个自定义 BSON Hook 的工作示例(它处理 java.net.URL)。可能是因为您没有在正确的位置注册它,所以您的钩子(Hook)无法正常工作?但是,我仍然建议去掉 Description,除非它添加了一些在上面的示例中不明显的值。
关于scala - 使用 Casbah/Salat 定义自定义序列化 - 或者将序列化委托(delegate)给成员?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9531846/
我正在尝试设置一个puppet节点,但rubygems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由rubygems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin
我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano
我使用Ember作为我的前端和GrapeAPI来为我的API提供服务。前端发送类似:{"service"=>{"name"=>"Name","duration"=>"30","user"=>nil,"organization"=>"org","category"=>nil,"description"=>"description","disabled"=>true,"color"=>nil,"availabilities"=>[{"day"=>"Saturday","enabled"=>false,"timeSlots"=>[{"startAt"=>"09:00AM","endAt"=>
我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c
我正在阅读一本关于Ruby的书,作者在编写类初始化定义时使用的形式与他在本书前几节中使用的形式略有不同。它看起来像这样:classTicketattr_accessor:venue,:datedefinitialize(venue,date)self.venue=venueself.date=dateendend在本书的前几节中,它的定义如下:classTicketattr_accessor:venue,:datedefinitialize(venue,date)@venue=venue@date=dateendend在第一个示例中使用setter方法与在第二个示例中使用实例变量之间是
给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最