Skip to content
This repository has been archived by the owner on Dec 6, 2022. It is now read-only.

feat: simplify block to only be data and cid #31

Merged
merged 4 commits into from
Mar 20, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ node_modules
.node_repl_history

dist
docs
19 changes: 9 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@
"test": "aegir-test",
"test:node": "aegir-test node",
"test:browser": "aegir-test browser",
"release": "aegir-release",
"release-minor": "aegir-release --type minor",
"release-major": "aegir-release --type major",
"release": "aegir-release --docs",
"release-minor": "aegir-release --type minor --docs",
"release-major": "aegir-release --type major --docs",
"coverage": "aegir-coverage",
"coverage-publish": "aegir-coverage publish"
"coverage-publish": "aegir-coverage publish",
"docs": "aegir-docs"
},
"pre-commit": [
"lint",
Expand All @@ -36,13 +37,11 @@
},
"homepage": "https://github.com/ipfs/js-ipfs-block#readme",
"devDependencies": {
"aegir": "^10.0.0",
"chai": "^3.5.0",
"multihashes": "~0.4.0"
"aegir": "^11.0.0",
"chai": "^3.5.0"
},
"dependencies": {
"async": "^2.1.4",
"multihashing-async": "~0.4.2"
"cids": "^0.4.2"
},
"engines": {
"node": ">=4.0.0",
Expand All @@ -58,4 +57,4 @@
"npmcdn-to-unpkg-bot <npmcdn-to-unpkg-bot@users.noreply.github.com>",
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>"
]
}
}
114 changes: 45 additions & 69 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,90 +1,66 @@
'use strict'

const multihashing = require('multihashing-async')
const setImmediate = require('async/setImmediate')

module.exports = Block
const CID = require('cids')

/**
* Represents an immutable block of data that is uniquely referenced with a multihash key.
* Represents an immutable block of data that is uniquely referenced with a cid.
*
* @constructor
* @param {Buffer | string} data - The data to be stored in the block as a buffer or a UTF8 string.
* @param {Buffer} data - The data to be stored in the block as a buffer.
* @param {CID} cid - The cid of the data
*
* @example
* const block = new Block('a012d83b20f9371...')
* const block = new Block(new Buffer('a012d83b20f9371...'))
*/
function Block (data) {
if (!(this instanceof Block)) {
return new Block(data)
}
class Block {
constructor (data, cid) {
if (!data || !Buffer.isBuffer(data)) {
throw new Error('first argument must be a buffer')
}

if (!data) {
throw new Error('Block must be constructed with data')
}
if (!cid || !CID.isCID(cid)) {
throw new Error('second argument must be a CID')
}

if (!(typeof data === 'string' || Buffer.isBuffer(data))) {
throw new Error('data should be Buffer')
this._data = data
this._cid = cid
}

if (!Buffer.isBuffer(data)) {
data = new Buffer(data)
/**
* The data of this block.
*
* @type {Buffer}
*/
get data () {
return this._data
}

this._cache = {}

data = ensureBuffer(data)

Object.defineProperty(this, 'data', {
get () {
return data
},
set () {
throw new Error('Tried to change an immutable block')
}
})
set data (val) {
throw new Error('Tried to change an immutable block')
}

/**
* Creates a unique multihash key of this block.
*
* @param {string} [hashFunc='sha2-256'] - The hash function to use.
* @param {function(Error, Multihash)} callback - The callback to execute on completion.
* @returns {void}
* @example
* block.key((multihash) => {
* console.log(multihash)
* })
* // 'QmeoBGh5g5kHgK3xppJ1...'
**/
this.key = (hashFunc, callback) => {
if (typeof hashFunc === 'function') {
callback = hashFunc
hashFunc = null
}

if (!hashFunc) {
hashFunc = 'sha2-256'
}

if (this._cache[hashFunc]) {
return setImmediate(() => {
callback(null, this._cache[hashFunc])
})
}

multihashing(this.data, hashFunc, (err, multihash) => {
if (err) {
return callback(err)
}
this._cache[hashFunc] = multihash
callback(null, multihash)
})
* The cid of the data this block represents.
*
* @type {CID}
*/
get cid () {
return this._cid
}
}

function ensureBuffer (data) {
if (Buffer.isBuffer(data)) {
return data
set cid (val) {
throw new Error('Tried to change an immutable block')
}

return new Buffer(data)
/**
* Check if the given value is a Block.
*
* @param {any} other
* @returns {bool}
*/
static isBlock (other) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still making my mind over this, but currently, I strongly feel that public module methods shouldn't be encapsulated in Class objects and made public with static.

I've seen a lot of cases of people starting to use static and then forgetting what it really means and start mutating the state.

Plus, it is way more understandable from a Node.js/CJS user if the "module.exports" is the only place that tells me what gets exported.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Declaring Block.isBlock = ... doesn't seem to be any better to me in terms of understanding.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also we started using this a while ago in modules like cid

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fine

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one bonus is that jsdoc picks up the right docs for this if we write it as static

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm.....

return other && other.constructor.name === 'Block'
}
}

module.exports = Block
88 changes: 0 additions & 88 deletions test/block.spec.js

This file was deleted.

45 changes: 45 additions & 0 deletions test/index.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/* eslint-env mocha */
'use strict'

const expect = require('chai').expect
const CID = require('cids')

const Block = require('../src')

describe('block', () => {
it('create throws', () => {
expect(
() => new Block('string')
).to.throw()

expect(
() => new Block(new Buffer('hello'), 'cid')
).to.throw()

expect(
() => new Block('hello', new CID('QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n'))
).to.throw()
})

it('create', () => {
const b = new Block(new Buffer('hello'), new CID('QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n'))

expect(Block.isBlock(b)).to.eql(true)
})

it('block stays immutable', () => {
const b = new Block(new Buffer('hello'), new CID('QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n'))

expect(
() => { b.data = 'fail' }
).to.throw(
/immutable/
)

expect(
() => { b.cid = 'fail' }
).to.throw(
/immutable/
)
})
})