1

我是一名拥有强大 JavaScript 背景的架构师,但我过去做过一些 .NET 和 Java。

但是,我想尝试一下 ActionScript3,我得到了承诺,它与 JavaScript 非常相关。

作为一个启动项目,我自己尝试移植到我最喜欢的断言实用程序之一的 ActionScript3 - should.js - 让您的测试代码非常易于阅读。

更新时间:2013-02-19

我看到我对我的抽象演讲感到困惑,所以我用脑海中的具体问题替换了一些帖子。这是完整的图片:

考虑以下 JavaScript 代码:

Object.defineProperty(Object.prototype, 'should'
, { set: function(){}
  , get: 
    function(){
       return new Assertion(Object(this).valueOf());
    }
  , configurable: true
  , enumerable  : false
  }
);

这是 JavaScript 模块实现的一部分Should。另一部分是类的定义Assertion,它是用一个值构造的,并针对该值实现了一组广泛而漂亮的断言方法。类似的方法

var o = Assertion(actualValue)
o.equals(expectedValue1)
o.moreThan(expectedValue2)
o.contains(expectedValue3)

和保持英语语法的别名

var o = Assertion(actualValue)
o.equal(expectedValue1)
o.contain(expectedValue3)

和懒惰神枪手的别名,比如

o.eql(expectedValue)
o.gt(expectedValue) //greater then
o.gte(...) //greater then or equal
//and so on... 

和一些只返回的连接器,(这是用测试值构造this的实例),比如Assertion

o.be
o.and

它给了你什么?

如下所示的测试代码:

var person = getPerson();
Should.exist(person); //that's a static call, and that's easy

//but these are a member calls:
person.should.have("name","age","address","friends");  
person.name.should.equal("John");
person.age
  .should
      .be.number()
  .and.be.between(20,30);

person.address
  .should
    .be.string().and
    .startWith("\d").and
    .endWith(" st.")
  //or even
    .and.match(/^[0-9]{1,9}\s+[A-Z][a-z0-9 ]* st\.$/);

person.friends
  .should
    .be.array().and
    .be.between(3,5).and
    .containOnlyType(String);

那不是很棒吗?这是简单的英语!

你可以争论缩进的美学,在哪里放置and,以及它们是否有必要,但除此之外 - 任何人都可以阅读或编写它:一旦你采用了每个对象上都存在但不会破坏地图的“应该”属性迭代 - 您可以继续链接您必须声明的关于您开始的价值的任何内容。

它可以有更多漂亮的迭代工具、反射实用程序、增加与您的对象模型相关的测试功能等等,但让我们完成第一步:)

但是为此,您需要系统中的每个对象都具有一个不可枚举的智能属性,称为should该属性,在它的getter函数中返回一个使用Assertion构造的对象this作为测试值。

(你什么都没有看到——等着看它给出的漂亮的拒绝信息!Yummie!!所以是的——我很乐意牺牲将属性称为“应该”的选项......并且也会很乐意放弃智能感知——至少只要是简单的英语)

所以,在评论中,bfavaretto给了我们第一步——我们知道如何防止枚举属性——太好了,谢谢!!

现在,我们可以让它成为一个 getter 属性,它的函数可以访问this?

当我完成后,我将把它放在麻省理工学院许可的一些公共回购中,让我们所有人都能玩得开心:)

帮助任何人?

4

3 回答 3

0

您的示例实际上 90% 正确 - 但将其定义为 actionscript,而不是 javascript!

您仍然可以在 AS3 中定义原型,并且它们仍然可以像 AS2 中的原型一样工作。AS3 的唯一区别是编译器。AVM2 出于某种原因不会将原型转换为本地类(尽管我没有测试自定义类)。

原型技巧:将类转换为对象。

例如:如果您创建:

Array.prototype.random = function():void{}

然后创建对象:

var myProtoArray:Array = 新数组;

会发生2件事:

myProtoArray.random() //ERROR - 这将失败,AVM2 没有将原型映射到 Array

Object(myProtoArray).random() //WORKS

random() 被强制转换为 Object 类,然后映射到 Array - 我不知道为什么!

希望这会有所帮助,干杯。

于 2013-02-14T21:50:55.990 回答
0

好的,伙计们,感谢所有帮助,22+ 我将为对原始问题感兴趣的人提供一个摘要,然后 - 我将向您展示我努力的结果。

挑战由两部分组成:

1 - 防止枚举增强(=在运行时添加)属性

对于第一部分 - 感谢@bfavaretto,对问题级别进行了评论 -Object.setPropertyIsEnumerable把戏做得很好。

2 - 使扩充属性操作一个可以访问的 getter 函数,this以便它可以在返回值的构造函数上使用它。

关于第二部分 - 基本上 - 我找不到一种方法来增加(=添加)一个属性获取器到原型,并让它通过继承树在使用它的 API 的实例上运行。

无论如何,在这些限制内 - 结果如下:

https://github.com/osher/should.as

由于平台差异,移植不准确,我仍然有一些方法可以赶上原始的 should.js(如 HTTP 测试方法)但足够接近。主要区别在于

var o:Object = 
    { name : "Radagast"
    , color: "Brown"
    }
o.should.have.properties("name","color")
    .and.have.property("name","Radagast");
o.name.should.not.equal("Palandoo");
o.color.should.equal("Brown");

你得走了

o.should().have.properties("name","color")
       and.have.property("name","Radagast");
o.name.should().not.equal("Palandoo");
o.color.should().equal("Brown");

(括号 - 不可能有 getter - 所以 should 属性是一个方法,你必须自己调用它)

现在,如果您遇到困难并需要智能感知的帮助,您必须这样做:

var should:tdd.Should = o.color.should();
should. <ctrl+space>

哪种方式可以消除刺痛,但可以窥探一下智能感应-它会有所帮助

重要的

还有一件事 - 你必须尽快在执行中强制应该的静态构造函数,例如,我在这里做:

[Suite]
[RunWith("org.flexunit.runners.Suite")]
public class my_awsome_test_suite
{
            //forces the static constructor of tdd.Should
    import tdd.Should;
    private static var s:Should = new Should(); 

    public var c1:testCase1;
    public var c2:testCase2;
    public var c3:testCase3;
    public var c4:testCase4;
    }

稍后我可能会添加一些propper README.md,以及更多令人敬畏的成员函数tdd.Should

玩得开心

于 2013-03-05T20:16:10.383 回答
0

我承认我对 Javascript 的工作原理并不十分熟悉,但如果我正确理解了 defineProperties 的目的,那么它不仅是属性应该是什么,而且是它所属的关联命名空间(或至少AS3 认为的命名空间)。

类属性要么是预定义的且只能通过自定义 get() set() 函数修改,要么是动态的。一旦编译,它们的命名空间就不能改变(据我所知),因此任何非私有属性都是隐式可枚举的,并且无论您是否编写了 getter/setter(即:)都是可修改的foo.a = value根据 Adob​​e...

您创建的属性是可枚举的,但内置属性通常不可枚举。

也就是说,您可以使用describeType从类中获取完整的属性列表。通过这种方式可以收集到相当详尽的信息,如果您想移植Mozilla 重新创建的 defineProperties示例,我怀疑应该满足您的需求。下面是一个仅打印属性值的示例。

function showProps(obj:*):void {
    var desc:XML= describeType(obj);

    // public vars
    for each (var n:XML in desc.variable){
        trace(n.@name + ": " + obj[n.@name]);
    }
    // getters
    for each (n in desc.accessor){
        try {
            trace(n.@name + ": " + obj[n.@name]);
        } catch (error:Error) {
            trace("Unable to read write-only property.");
        }
    }
}

我希望这会有所帮助,但我确定我并不完全理解您要完成的工作。如果您能详细说明,将不胜感激。

于 2013-02-14T21:54:19.867 回答