Skip to content

Commit

Permalink
Add the namespace chaineable function
Browse files Browse the repository at this point in the history
  • Loading branch information
victor-am committed Dec 2, 2017
1 parent 016f1a1 commit 58501b3
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 3 deletions.
18 changes: 18 additions & 0 deletions src/rails-ranger.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,24 @@ class RailsRanger {
return newInstance
}

/**
* Defines a namespace to be used in the next request of the chain
* @param {string} namespace - The path fragment to be used as the namespace
* @param {object} params - The parameters to be interpolated into the path, can be left empty
* @example
* const api = new RailsRanger
* api.namespace('admin/:type', { type: 'super' }).list('blogPosts')
* //=> GET request to '/admin/super/blog_posts' path
*/
namespace (namespace, params = {}) {
const newInstance = clone(this)
const newRouteBuilder = this.routeBuilder.namespace(namespace, params)

newInstance.routeBuilder = newRouteBuilder

return newInstance
}

/**
* Makes a GET request to the given path with the given parameters
* @param {string} path - The base path of the request
Expand Down
27 changes: 25 additions & 2 deletions src/rails-route-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,37 @@ class RailsRouteBuilder {
* //=> { path: '/users/1/blog_posts', params: {} }
*/
resource (resource, id = null) {
const snakedResource = snakeCase(resource)

if (id) {
return this.namespace(`${snakedResource}/:id`, { id })
} else {
return this.namespace(snakedResource)
}
}

/**
* Defines a namespace to be used in the next route of the chain
* @param {string} namespace - The path fragment to be used as the namespace
* @param {object} params - The parameters to be interpolated into the path, can be left empty
* @example
* const routes = new RailsRouteBuilder
* routes.namespace('admin').list('blogPosts')
* //=> { path: '/admin/blog_posts', params: {} }
*/
namespace (namespace, params = {}) {
const newInstance = clone(this)
const path = id ? `${snakeCase(resource)}/${id}` : resource

// Duplicates the chainedPaths as a new object
newInstance.chainedPaths = clone(this.chainedPaths)

// Process the given namespace interpolating params on the path
// Ex:
// 'users/:id' with params { id: 1 } becomes 'users/1'
const pathAndParams = this.pathBuilder._paramsToPath({ path: namespace, params })

// Pushes the new namespace to the chainedPaths
newInstance.chainedPaths.push(path)
newInstance.chainedPaths.push(pathAndParams['path'])

return newInstance
}
Expand Down
15 changes: 15 additions & 0 deletions test/unit/rails-ranger.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,11 @@ describe('RailsRanger', () => {
ranger.resource('projects', 1).destroy('users', { id: 2 })
expect(ranger.client.delete).to.have.been.calledWith('projects/1/users/2')
})

it('works with a namespace', () => {
ranger.namespace('blog_posts').destroy('users', { id: 2 })
expect(ranger.client.delete).to.have.been.calledWith('blog_posts/users/2')
})
})

describe('.new', () => {
Expand All @@ -249,6 +254,11 @@ describe('RailsRanger', () => {
ranger.resource('projects', 1).new('users')
expect(ranger.client.get).to.have.been.calledWith('projects/1/users/new')
})

it('works with a namespace', () => {
ranger.namespace('blog_posts/:id', { id: 1 }).new('users')
expect(ranger.client.get).to.have.been.calledWith('blog_posts/1/users/new')
})
})

describe('.edit', () => {
Expand All @@ -271,6 +281,11 @@ describe('RailsRanger', () => {
ranger.resource('projects', 1).edit('users', { id: 2 })
expect(ranger.client.get).to.have.been.calledWith('projects/1/users/2/edit')
})

it('works with a namespace', () => {
ranger.namespace('blog_posts/:id', { id: 1 }).edit('users', { id: 2 })
expect(ranger.client.get).to.have.been.calledWith('blog_posts/1/users/2/edit')
})
})

describe('.resource', () => {
Expand Down
61 changes: 60 additions & 1 deletion test/unit/rails-route-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ describe('RailsRouteBuilder', () => {

it('pushes the right data into the chainedPaths list', () => {
let newInstance = routeBuilder.resource('users').resource('blogPosts')
expect(newInstance.chainedPaths).to.have.same.members(['users', 'blogPosts'])
expect(newInstance.chainedPaths).to.have.same.members(['users', 'blog_posts'])
})
})
})
Expand Down Expand Up @@ -232,4 +232,63 @@ describe('RailsRouteBuilder', () => {
})
})
})

describe('.namespace', () => {
it('does not taint the original instance', () => {
routeBuilder.namespace('users')
expect(routeBuilder.chainedPaths).to.be.empty
})

context('namespace without params', () => {
context('single call to .namespace', () => {
it('returns a new RailsRouteBuilder instance', () => {
let returnedValue = routeBuilder.namespace('users')
expect(returnedValue).to.be.an.instanceOf(RailsRouteBuilder)
})

it('pushes the right data into the chainedPaths attribute', () => {
let newInstance = routeBuilder.namespace('users')
expect(newInstance.chainedPaths).to.have.same.members(['users'])
})
})

context('chained calls to .namespace', () => {
it('returns a new RailsRouteBuilder instance', () => {
let returnedValue = routeBuilder.namespace('users').namespace('blog_post')
expect(returnedValue).to.be.an.instanceOf(RailsRouteBuilder)
})

it('pushes the right data into the chainedPaths list', () => {
let newInstance = routeBuilder.namespace('users').namespace('blog_posts')
expect(newInstance.chainedPaths).to.have.same.members(['users', 'blog_posts'])
})
})
})

context('namespace with params', () => {
context('single call to .namespace', () => {
it('returns a new RailsRouteBuilder instance', () => {
let returnedValue = routeBuilder.namespace('users/:id', { id: 1 })
expect(returnedValue).to.be.an.instanceOf(RailsRouteBuilder)
})

it('pushes the right data into the chainedPaths attribute', () => {
let newInstance = routeBuilder.namespace('users/:id', { id: 1 })
expect(newInstance.chainedPaths).to.have.same.members(['users/1'])
})
})

context('chained calls to .namespace', () => {
it('returns a new RailsRouteBuilder instance', () => {
let returnedValue = routeBuilder.namespace('users/:id', { id: 1 }).namespace('blog_post/:id', { id: 2 })
expect(returnedValue).to.be.an.instanceOf(RailsRouteBuilder)
})

it('pushes the right data into the chainedPaths list', () => {
let newInstance = routeBuilder.namespace('users/:id', { id: 1 }).namespace('blog_posts/:id', { id: 2 })
expect(newInstance.chainedPaths).to.have.same.members(['users/1', 'blog_posts/2'])
})
})
})
})
})

0 comments on commit 58501b3

Please sign in to comment.