Skip to content

Commit

Permalink
Refactor into classes
Browse files Browse the repository at this point in the history
- Move logic for parsing and linting into new LessFile class
- Extend LessFile as LessCachedFile with caching specific implementation
- Move non grunt task files to tasks/lib to prevent being read by grunt
- Add extra tests for imports invalidation in less-file-spec.coffee
  • Loading branch information
jgable committed Mar 2, 2014
1 parent f3951e0 commit 30e4162
Show file tree
Hide file tree
Showing 10 changed files with 388 additions and 138 deletions.
4 changes: 2 additions & 2 deletions Gruntfile.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module.exports = (grunt) ->
glob_to_multiple:
expand: true
cwd: 'src'
src: ['*.coffee']
src: ['**/*.coffee']
dest: 'tasks'
ext: '.js'

Expand Down Expand Up @@ -34,5 +34,5 @@ module.exports = (grunt) ->
grunt.loadNpmTasks('grunt-shell')
grunt.registerTask 'clean', -> require('rimraf').sync('tasks')
grunt.registerTask('lint', ['coffeelint'])
grunt.registerTask('test', ['default', 'shell:test'])
grunt.registerTask('test', ['default', 'lesslint:clearCache', 'shell:test'])
grunt.registerTask('default', ['lint', 'coffee'])
123 changes: 123 additions & 0 deletions spec/less-file-spec.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
path = require 'path'
grunt = require 'grunt'
{LessFile, LessCachedFile} = require '../tasks/lib/less-file'

describe 'less-file', ->
describe 'LessFile', ->
filePath = path.join(__dirname, 'fixtures', 'valid.less')
file = null

beforeEach ->
file = new LessFile(filePath, {}, grunt)

it 'can load contents', ->
contents = file.getContents()
expect(contents).toBe grunt.file.read(filePath)

it 'can get a hash', ->
hash = file.getDigest()
expect(hash).toNotBe null
expect(hash.length).toBeGreaterThan 0

it 'can lint a file', (done) ->
file.lint (err, result, less, css) ->
expect(err).toBe null
expect(result).toBe undefined
expect(less).toNotBe undefined
expect(less.length).toBeGreaterThan 0
expect(css).toNotBe undefined
expect(css.length).toBeGreaterThan 0

done()

describe 'LessCachedFile', ->
filePath = path.join(__dirname, 'fixtures', 'valid.less')
file = null

beforeEach ->
file = new LessCachedFile(filePath, {}, grunt)

it 'can load contents', ->
contents = file.getContents()
expect(contents).toBe grunt.file.read(filePath)

it 'can get a hash', ->
hash = file.getDigest()
expect(hash).toNotBe null
expect(hash.length).toBeGreaterThan 0

it 'can lint a file', (done) ->
# See if we read the file
spyOn(file, 'getCss').andCallThrough()
# Force no caching
spyOn(file.cache, 'hasCached').andCallFake (hash, cb) -> cb(false)
spyOn(file.cache, 'addCached').andCallFake (hash, cb) -> cb(null)

file.lint (err, result, less, css) ->
expect(file.getCss).toHaveBeenCalled()
expect(err).toBe null
expect(result).toBe undefined
expect(less).toNotBe undefined
expect(less.length).toBeGreaterThan 0
expect(css).toNotBe undefined
expect(css.length).toBeGreaterThan 0

done()

it 'does not parse less if previously cached successful run', (done) ->
# See if we read the file
spyOn(file, 'getCss').andCallThrough()
# Force cache hit
spyOn(file.cache, 'hasCached').andCallFake (hash, cb) -> cb(true)
spyOn(file.cache, 'addCached').andCallFake (hash, cb) -> cb(null)

file.lint (err, result, less, css) ->
expect(file.getCss).not.toHaveBeenCalled()

done()

it 'uses imports from config option as a cache key so changes in import files cause re-linting', (done) ->
file.options.imports = ['spec/fixtures/file.less']
# See if we read the file
spyOn(file, 'getCss').andCallThrough()

hashKey = null
spyOn(file.cache, 'hasCached').andCallFake (hash, cb) ->
hashKey = hash
cb false

spyOn(file.cache, 'addCached').andCallFake (hash, cb) -> cb(null)

# Stub the getContents so we can change it on subsequent runs through
contentsCalls = 0
spyOn(file, 'getImportsContents').andCallFake ->
contentsCalls += 1
["body { margin: #{contentsCalls}px; }"]

file.lint (err, result, less, css) ->
expect(file.getCss).toHaveBeenCalled()
expect(contentsCalls).toBe 1
expect(err).toBe null
expect(result).toBe undefined

otherFile = new LessCachedFile(filePath, {}, grunt)
otherFile.options.imports = ['spec/fixtures/file.less']

spyOn(otherFile, 'getCss').andCallThrough()

otherHashKey = null
spyOn(otherFile.cache, 'hasCached').andCallFake (hash, cb) ->
otherHashKey = hash
cb false

spyOn(otherFile.cache, 'addCached').andCallFake (hash, cb) -> cb(null)
spyOn(otherFile, 'getImportsContents').andCallFake ->
contentsCalls += 1
["body { margin: #{contentsCalls}px; }"]

otherFile.lint (err, otherResult, less, css) ->
expect(otherFile.getCss).toHaveBeenCalled()
expect(contentsCalls).toBe 2
expect(otherHashKey).not.toBe hashKey

done()
32 changes: 21 additions & 11 deletions spec/less-lint-task-spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ crypto = require 'crypto'
grunt = require 'grunt'
tmp = require 'tmp'
{parseString} = require 'xml2js'
{LintCache} = require '../tasks/lint-cache'
{LintCache} = require '../tasks/lib/lint-cache'

_ = grunt.util._

Expand Down Expand Up @@ -273,7 +273,19 @@ describe 'LESS Lint task', ->
grunt.loadTasks(path.resolve(__dirname, '..', 'tasks'))
taskCount = 0
tasksDone = false

addCacheHash = null
cacheHits = 0
addCacheHit = (filePath, cachePath) ->
cacheHits += 1
grunt.event.on 'lesslint.cache.hit', addCacheHit

cacheAdds = 0
addCacheAdd = (filePath, cacheHash) ->
cacheAdds += 1
addCacheHash = cacheHash
grunt.event.on 'lesslint.cache.add', addCacheAdd

grunt.registerTask 'done', 'done', ->
taskCount++

Expand All @@ -284,22 +296,20 @@ describe 'LESS Lint task', ->
output = []
spyOn(process.stdout, 'write').andCallFake (data='') ->
output.push(data.toString())
spyOn(LintCache.prototype, 'hasCached').andCallFake (hash, done) ->
# only return false the first time
done(taskCount == 1)
spyOn(LintCache.prototype, 'addCached').andCallFake (hash, done) ->
addCacheHash = hash
done()

grunt.task.run(['lesslint', 'done']).start()
waitsFor -> tasksDone
runs ->
# Remove the event listeners
grunt.event.off 'lesslint.cache.hit', addCacheHit
grunt.event.off 'lesslint.cache.add', addCacheAdd

taskOutput = output.join('')
expect(taskOutput).toContain '1 file lint free'
# should be called both times
expect(LintCache.prototype.hasCached.callCount).toBe(2)
expect(cacheHits).toBe(1)
# should only be called the first time
expect(LintCache.prototype.addCached.callCount).toBe(1)
expect(cacheAdds).toBe(1)

less = grunt.file.read(path.join(__dirname, 'fixtures', 'valid.less'))
expect(addCacheHash).toNotEqual null
expect(addCacheHash).toNotEqual ''
expect(addCacheHash).toNotEqual ''
2 changes: 1 addition & 1 deletion spec/lint-utils-spec.coffee
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
fs = require 'fs'
path = require 'path'
linter = require '../tasks/lint-utils'
linter = require '../tasks/lib/lint-utils'

describe 'lint-utils', ->
describe '.findLessMapping()', ->
Expand Down
Loading

0 comments on commit 30e4162

Please sign in to comment.