Merge pull request #720 from braydonf/feature/immutable-opcode

Opcode: Modify `from` methods to be static, and an instance be immutable.
This commit is contained in:
Manuel Aráoz 2014-12-12 11:19:30 -03:00
commit d6caab69ca
2 changed files with 48 additions and 43 deletions

View File

@ -8,43 +8,42 @@ function Opcode(num) {
return new Opcode(num); return new Opcode(num);
} }
if (typeof num === 'number') { var value;
this.num = num;
} else if (typeof num === 'string') { if (_.isNumber(num)) {
var str = num; value = num;
this.num = Opcode.map[str]; } else if (_.isString(num)) {
} else if (num) { value = Opcode.map[num];
var obj = num; } else {
this.set(obj); throw new TypeError('Unrecognized num type: "' + typeof(num) + '" for Opcode');
}
} }
Opcode.prototype.set = function(obj) { Object.defineProperty(this, 'num', {
$.checkArgument(_.isObject(obj)); configurable: false,
this.num = typeof obj.num !== 'undefined' ? obj.num : this.num; value: value
});
return this; return this;
}
Opcode.fromNumber = function(num) {
$.checkArgument(_.isNumber(num));
return new Opcode(num);
}; };
Opcode.prototype.fromNumber = function(num) { Opcode.fromString = function(str) {
$.checkArgument(_.isNumber(num)); $.checkArgument(_.isString(str));
this.num = num; var value = Opcode.map[str];
return this; if (typeof value === 'undefined') {
throw new TypeError('Invalid opcodestr');
}
return new Opcode(value);
}; };
Opcode.prototype.toNumber = function() { Opcode.prototype.toNumber = function() {
return this.num; return this.num;
}; };
Opcode.prototype.fromString = function(str) {
$.checkArgument(_.isString(str));
var num = Opcode.map[str];
if (typeof num === 'undefined') {
throw new Error('Invalid opcodestr');
}
this.num = num;
return this;
};
Opcode.prototype.toString = function() { Opcode.prototype.toString = function() {
var str = Opcode.reverseMap[this.num]; var str = Opcode.reverseMap[this.num];
if (typeof str === 'undefined') { if (typeof str === 'undefined') {
@ -203,10 +202,8 @@ Opcode.map = {
Opcode.reverseMap = []; Opcode.reverseMap = [];
for (var k in Opcode.map) { for (var k in Opcode.map) {
if (Opcode.map.hasOwnProperty(k)) {
Opcode.reverseMap[Opcode.map[k]] = k; Opcode.reverseMap[Opcode.map[k]] = k;
} }
}
// Easier access to opcodes // Easier access to opcodes
_.extend(Opcode, Opcode.map); _.extend(Opcode, Opcode.map);

View File

@ -1,7 +1,9 @@
'use strict'; 'use strict';
var _ = require('lodash'); var _ = require('lodash');
var should = require('chai').should(); var chai = require('chai');
var should = chai.should();
var expect = chai.expect;
var bitcore = require('..'); var bitcore = require('..');
var Opcode = bitcore.Opcode; var Opcode = bitcore.Opcode;
@ -26,46 +28,52 @@ describe('Opcode', function() {
describe('#fromNumber', function() { describe('#fromNumber', function() {
it('should work for 0', function() { it('should work for 0', function() {
Opcode().fromNumber(0).num.should.equal(0); Opcode.fromNumber(0).num.should.equal(0);
}); });
it('should fail for non-number', function() { it('should fail for non-number', function() {
Opcode().fromNumber.bind(null, 'a string').should.throw('Invalid Argument'); Opcode.fromNumber.bind(null, 'a string').should.throw('Invalid Argument');
}); });
}); });
describe('#set', function() { describe('#set', function() {
it('should work for object', function() { it('should work for object', function() {
Opcode().set({ Opcode(42).num.should.equal(42);
num: 42
}).num.should.equal(42);
}); });
it('should fail for non-object', function() { it('should fail for empty-object', function() {
Opcode().set.bind(null, 'non-object').should.throw('Invalid Argument'); expect(function() {
Opcode();
}).to.throw(TypeError);
}); });
}); });
describe('#toNumber', function() { describe('#toNumber', function() {
it('should work for 0', function() { it('should work for 0', function() {
Opcode().fromNumber(0).toNumber().should.equal(0); Opcode.fromNumber(0).toNumber().should.equal(0);
}); });
}); });
describe('#fromString', function() { describe('#fromString', function() {
it('should work for OP_0', function() { it('should work for OP_0', function() {
Opcode().fromString('OP_0').num.should.equal(0); Opcode.fromString('OP_0').num.should.equal(0);
}); });
it('should fail for invalid string', function() { it('should fail for invalid string', function() {
Opcode().fromString.bind(null, 'OP_SATOSHI').should.throw('Invalid opcodestr'); Opcode.fromString.bind(null, 'OP_SATOSHI').should.throw('Invalid opcodestr');
Opcode().fromString.bind(null, 'BANANA').should.throw('Invalid opcodestr'); Opcode.fromString.bind(null, 'BANANA').should.throw('Invalid opcodestr');
}); });
it('should fail for non-string', function() { it('should fail for non-string', function() {
Opcode().fromString.bind(null, 123).should.throw('Invalid Argument'); Opcode.fromString.bind(null, 123).should.throw('Invalid Argument');
}); });
}); });
describe('#toString', function() { describe('#toString', function() {
it('should work for OP_0', function() { it('should work for OP_0', function() {
Opcode().fromString('OP_0').toString().should.equal('OP_0'); Opcode.fromString('OP_0').toString().should.equal('OP_0');
});
it('should not work for non-opcode', function() {
expect(function(){
Opcode('OP_NOTACODE').toString();
}).to.throw('Opcode does not have a string representation');
}); });
}); });