From 5826b11cdb389da888e66d6b609d0b422bbb4e38 Mon Sep 17 00:00:00 2001 From: alexander sanchez Date: Thu, 14 May 2015 10:44:06 -0400 Subject: [PATCH 01/13] working on custom path --- lib/package-generator-view.coffee | 84 ++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 24 deletions(-) diff --git a/lib/package-generator-view.coffee b/lib/package-generator-view.coffee index d53517b..54d9826 100644 --- a/lib/package-generator-view.coffee +++ b/lib/package-generator-view.coffee @@ -8,23 +8,57 @@ module.exports = class PackageGeneratorView extends View previouslyFocusedElement: null mode: null + customDir: null @content: -> @div class: 'package-generator', => - @subview 'miniEditor', new TextEditorView(mini: true) - @div class: 'error', outlet: 'error' - @div class: 'message', outlet: 'message' + @div outlet: 'container', => + @subview 'nameEditor', new TextEditorView(mini: true) + @subview 'pathEditor', new TextEditorView(mini: true) + @div class: 'block', => + @div class: 'btn-group', => + @button outlet: 'dpBtn', class: 'btn',click: 'setupDefaultPath', 'default path' + @button outlet: 'npBtn', class: 'btn',click: 'setupCustomPath', 'new path' + @div class: 'error', outlet: 'error' + @div class: 'message', outlet: 'message' + @div outlet: 'output' initialize: -> @commandSubscription = atom.commands.add 'atom-workspace', 'package-generator:generate-package': => @attach('package') 'package-generator:generate-syntax-theme': => @attach('theme') - @miniEditor.on 'blur', => @close() + @container.on 'blur', => @close() + @pathEditor.getModel().on 'change', => @updateOutput() + @nameEditor.getModel().on 'change', => @updateOutput() + # @pathEditor.on 'dh', => @updateOutput() + atom.commands.add @element, 'core:confirm': => @confirm() 'core:cancel': => @close() + updateOutput: -> + @output.text @buildPackagePath() + + # a little helper to make adding/removing btn select css + # a little less annoying. + swapBtnSelect: (sel, nosel) -> + sel.addClass 'selected' + nosel.removeClass 'selected' + undefined + + # changes the panel view to use a custom path. + setupCustomPath: () -> + @swapBtnSelect @npBtn, @dpBtn + @pathEditor.setText @getPackagesDirectory() + @pathEditor.show() + + # reverts the panel to the default view + setupDefaultPath: () -> + @swapBtnSelect @dpBtn, @npBtn + @pathEditor.setText @getPackagesDirectory() + @pathEditor.hide() + destroy: -> @panel?.destroy() @commandSubscription.dispose() @@ -35,45 +69,47 @@ class PackageGeneratorView extends View @panel.show() @message.text("Enter #{mode} path") if @mode == 'package' - @setPathText("my-package") + @setNameText("my-awesome-package") else - @setPathText("my-theme-syntax", [0, 8]) - @miniEditor.focus() - - setPathText: (placeholderName, rangeToSelect) -> - editor = @miniEditor.getModel() - rangeToSelect ?= [0, placeholderName.length] - packagesDirectory = @getPackagesDirectory() - editor.setText(path.join(packagesDirectory, placeholderName)) - pathLength = editor.getText().length - endOfDirectoryIndex = pathLength - placeholderName.length - editor.setSelectedBufferRange([[0, endOfDirectoryIndex + rangeToSelect[0]], [0, endOfDirectoryIndex + rangeToSelect[1]]]) + @setNameText("my-awesome-syntax") + @nameEditor.focus() close: -> return unless @panel.isVisible() @panel.hide() @previouslyFocusedElement?.focus() + setNameText: (placeholderName) -> + nameEditor = @nameEditor.getModel() + @setupDefaultPath() # setting up the pathEditor + nameEditor.setText(placeholderName) + nameEditor.setSelectedBufferRange([[0, 0], [0, placeholderName.length]]) + confirm: -> if @validPackagePath() @createPackageFiles => - packagePath = @getPackagePath() + packagePath = @buildPackagePath() atom.open(pathsToOpen: [packagePath]) @close() - getPackagePath: -> - packagePath = @miniEditor.getText().trim() - packageName = _.dasherize(path.basename(packagePath)) - path.join(path.dirname(packagePath), packageName) + buildPackagePath: -> + # packagePath = @miniEditor.getText().trim() + # packageName = _.dasherize(path.basename(packagePath)) + # path.join(path.dirname(packagePath), packageName) + pkgName = _.dasherize @nameEditor.getText().trim() + pkgPath = @pathEditor.getText().trim() + path.join(path.dirname(pkgPath), pkgName) + # retuns the location of either the specified, env variable, or default + # packages directory getPackagesDirectory: -> atom.config.get('core.projectHome') or process.env.ATOM_REPOS_HOME or path.join(fs.getHomeDirectory(), 'github') validPackagePath: -> - if fs.existsSync(@getPackagePath()) - @error.text("Path already exists at '#{@getPackagePath()}'") + if fs.existsSync(@buildPackagePath()) + @error.text("Path already exists at '#{@buildPackagePath()}'") @error.show() false else @@ -97,7 +133,7 @@ class PackageGeneratorView extends View packagePath.indexOf(devPackagesPath) is 0 createPackageFiles: (callback) -> - packagePath = @getPackagePath() + packagePath = @buildPackagePath() packagesDirectory = @getPackagesDirectory() if @isStoredInDotAtom(packagePath) From 45f5b2a6041a83a5bf52ffa69a05ec16e52a1a64 Mon Sep 17 00:00:00 2001 From: alexander sanchez Date: Thu, 14 May 2015 12:55:00 -0400 Subject: [PATCH 02/13] removing some dead code --- lib/package-generator-view.coffee | 62 ++++++++++++++++++------------- styles/package-generator.less | 7 +++- 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/lib/package-generator-view.coffee b/lib/package-generator-view.coffee index 54d9826..d4bf96d 100644 --- a/lib/package-generator-view.coffee +++ b/lib/package-generator-view.coffee @@ -21,7 +21,6 @@ class PackageGeneratorView extends View @button outlet: 'npBtn', class: 'btn',click: 'setupCustomPath', 'new path' @div class: 'error', outlet: 'error' @div class: 'message', outlet: 'message' - @div outlet: 'output' initialize: -> @commandSubscription = atom.commands.add 'atom-workspace', @@ -29,19 +28,11 @@ class PackageGeneratorView extends View 'package-generator:generate-syntax-theme': => @attach('theme') @container.on 'blur', => @close() - @pathEditor.getModel().on 'change', => @updateOutput() - @nameEditor.getModel().on 'change', => @updateOutput() - # @pathEditor.on 'dh', => @updateOutput() atom.commands.add @element, 'core:confirm': => @confirm() 'core:cancel': => @close() - updateOutput: -> - @output.text @buildPackagePath() - - # a little helper to make adding/removing btn select css - # a little less annoying. swapBtnSelect: (sel, nosel) -> sel.addClass 'selected' nosel.removeClass 'selected' @@ -50,7 +41,6 @@ class PackageGeneratorView extends View # changes the panel view to use a custom path. setupCustomPath: () -> @swapBtnSelect @npBtn, @dpBtn - @pathEditor.setText @getPackagesDirectory() @pathEditor.show() # reverts the panel to the default view @@ -72,6 +62,7 @@ class PackageGeneratorView extends View @setNameText("my-awesome-package") else @setNameText("my-awesome-syntax") + @setupDefaultPath() @nameEditor.focus() close: -> @@ -81,39 +72,60 @@ class PackageGeneratorView extends View setNameText: (placeholderName) -> nameEditor = @nameEditor.getModel() - @setupDefaultPath() # setting up the pathEditor nameEditor.setText(placeholderName) nameEditor.setSelectedBufferRange([[0, 0], [0, placeholderName.length]]) confirm: -> - if @validPackagePath() - @createPackageFiles => - packagePath = @buildPackagePath() - atom.open(pathsToOpen: [packagePath]) + finalPackageLocation = @buildPackagePath() + if @validPackagePath(finalPackageLocation) + @createPackageFiles finalPackageLocation, => + atom.open(pathsToOpen: [finalPackageLocation]) @close() buildPackagePath: -> - # packagePath = @miniEditor.getText().trim() - # packageName = _.dasherize(path.basename(packagePath)) - # path.join(path.dirname(packagePath), packageName) pkgName = _.dasherize @nameEditor.getText().trim() pkgPath = @pathEditor.getText().trim() path.join(path.dirname(pkgPath), pkgName) - # retuns the location of either the specified, env variable, or default - # packages directory getPackagesDirectory: -> atom.config.get('core.projectHome') or process.env.ATOM_REPOS_HOME or path.join(fs.getHomeDirectory(), 'github') - validPackagePath: -> - if fs.existsSync(@buildPackagePath()) - @error.text("Path already exists at '#{@buildPackagePath()}'") + userIsOwner: (stats) -> + owner = (process.getuid() is stats.uid) + owner && (stats.mode & 0o00200) + + usersGroupCanWrite: (stats) -> + inGroup = (process.getgid() is stats.gid) + inGroup && (stats.mode & 0o00020) + + anyoneCanWrite: (stats) -> + (stats.mode & 0o00002) + + validPermission: (saveLocation) -> + stats = fs.statSync path.dirname(saveLocation) + if @userIsOwner(stats) or + @usersGroupCanWrite(stats) or + @anyoneCanWrite(stats) + return true + else + @error.text("You do not have the required privilege to save in #{path.dirname(saveLocation)}.") @error.show() false - else + + alreadyPackage: (saveLocation) -> + if fs.existsSync(saveLocation) + @error.text("Path already exists at '#{saveLocation}'") + @error.show() true + else + false + + validPackagePath: (finalPackageLocation) -> + return false if @alreadyPackage finalPackageLocation + return false if not @validPermission finalPackageLocation + true initPackage: (packagePath, callback) -> @runCommand(atom.packages.getApmPath(), ['init', "--#{@mode}", "#{packagePath}"], callback) @@ -132,7 +144,7 @@ class PackageGeneratorView extends View devPackagesPath = path.join(atom.getConfigDirPath(), 'dev', 'packages', path.sep) packagePath.indexOf(devPackagesPath) is 0 - createPackageFiles: (callback) -> + createPackageFiles: (saveLocation, callback) -> packagePath = @buildPackagePath() packagesDirectory = @getPackagesDirectory() diff --git a/styles/package-generator.less b/styles/package-generator.less index 1db9954..48d6896 100644 --- a/styles/package-generator.less +++ b/styles/package-generator.less @@ -1,3 +1,8 @@ .package-generator .error { display: none; -} \ No newline at end of file + color: red; +} + +.package-generator .progress { + display: none; +} From db264e4e629d490bee8822406d997d4d71aeaceb Mon Sep 17 00:00:00 2001 From: alexander sanchez Date: Thu, 14 May 2015 17:51:30 -0400 Subject: [PATCH 03/13] separating file permission validation --- lib/package-generator-view.coffee | 44 +++++++++---------------------- lib/permission.coffee | 28 ++++++++++++++++++++ 2 files changed, 41 insertions(+), 31 deletions(-) create mode 100644 lib/permission.coffee diff --git a/lib/package-generator-view.coffee b/lib/package-generator-view.coffee index d4bf96d..e026ff8 100644 --- a/lib/package-generator-view.coffee +++ b/lib/package-generator-view.coffee @@ -3,6 +3,7 @@ _ = require 'underscore-plus' {$, TextEditorView, View} = require 'atom-space-pen-views' {BufferedProcess} = require 'atom' fs = require 'fs-plus' +perm = require './permission' module.exports = class PackageGeneratorView extends View @@ -17,8 +18,8 @@ class PackageGeneratorView extends View @subview 'pathEditor', new TextEditorView(mini: true) @div class: 'block', => @div class: 'btn-group', => - @button outlet: 'dpBtn', class: 'btn',click: 'setupDefaultPath', 'default path' - @button outlet: 'npBtn', class: 'btn',click: 'setupCustomPath', 'new path' + @button outlet: 'dpBtn', class: 'btn', click: 'setupDefaultPath', 'default path' + @button outlet: 'npBtn', class: 'btn', click: 'setupCustomPath', 'new path' @div class: 'error', outlet: 'error' @div class: 'message', outlet: 'message' @@ -92,40 +93,21 @@ class PackageGeneratorView extends View process.env.ATOM_REPOS_HOME or path.join(fs.getHomeDirectory(), 'github') - userIsOwner: (stats) -> - owner = (process.getuid() is stats.uid) - owner && (stats.mode & 0o00200) - - usersGroupCanWrite: (stats) -> - inGroup = (process.getgid() is stats.gid) - inGroup && (stats.mode & 0o00020) - - anyoneCanWrite: (stats) -> - (stats.mode & 0o00002) - - validPermission: (saveLocation) -> - stats = fs.statSync path.dirname(saveLocation) - if @userIsOwner(stats) or - @usersGroupCanWrite(stats) or - @anyoneCanWrite(stats) - return true - else - @error.text("You do not have the required privilege to save in #{path.dirname(saveLocation)}.") + validPackagePath: (finalPackageLocation) -> + if not @nameEditor + @error.text("You never input a group '#{saveLocation}'") @error.show() false - - alreadyPackage: (saveLocation) -> - if fs.existsSync(saveLocation) + if fs.existsSync(finalPackageLocation) @error.text("Path already exists at '#{saveLocation}'") @error.show() - true - else - false + return false + if not perm.validPermission finalPackageLocation + @error.text("You do not have the right to save at #{finalPackageLocation}") + @error.show() + return false - validPackagePath: (finalPackageLocation) -> - return false if @alreadyPackage finalPackageLocation - return false if not @validPermission finalPackageLocation - true + true # yay! valid package initPackage: (packagePath, callback) -> @runCommand(atom.packages.getApmPath(), ['init', "--#{@mode}", "#{packagePath}"], callback) diff --git a/lib/permission.coffee b/lib/permission.coffee new file mode 100644 index 0000000..b39f936 --- /dev/null +++ b/lib/permission.coffee @@ -0,0 +1,28 @@ +fs = require 'fs-plus' + +userIsOwner = (stats) -> + owner = (process.getuid() is stats.uid) + owner && (stats.mode & 0o00200) + +usersGroupCanWrite = (stats) -> + inGroup = (process.getgid() is stats.gid) + inGroup && (stats.mode & 0o00020) + +anyoneCanWrite = (stats) -> + stats.mode & 0o00002 + +validPermission= (saveLocation) -> + stats = fs.statSync path.dirname(saveLocation) + if userIsOwner(stats) or + usersGroupCanWrite(stats) or + anyoneCanWrite(stats) + return true + else + false + +exports = { + userIsOwner + usersGroupCanWrite + anyoneCanWrite + validPermission +} From 9290338ccaa49ad4f4ed06c3b47f2be95dc57ef0 Mon Sep 17 00:00:00 2001 From: alexander sanchez Date: Thu, 14 May 2015 19:47:34 -0400 Subject: [PATCH 04/13] working. now specs --- lib/main.coffee | 1 + lib/package-generator-view.coffee | 50 +++++++++++++++++-------------- lib/permission.coffee | 2 +- lib/validation.coffee | 13 ++++++++ 4 files changed, 43 insertions(+), 23 deletions(-) create mode 100644 lib/validation.coffee diff --git a/lib/main.coffee b/lib/main.coffee index 98b2e2d..902eb00 100644 --- a/lib/main.coffee +++ b/lib/main.coffee @@ -1,5 +1,6 @@ PackageGeneratorView = require './package-generator-view' + module.exports = config: createInDevMode: diff --git a/lib/package-generator-view.coffee b/lib/package-generator-view.coffee index e026ff8..e538bed 100644 --- a/lib/package-generator-view.coffee +++ b/lib/package-generator-view.coffee @@ -3,13 +3,15 @@ _ = require 'underscore-plus' {$, TextEditorView, View} = require 'atom-space-pen-views' {BufferedProcess} = require 'atom' fs = require 'fs-plus' -perm = require './permission' +{validPermission} = require './permission' +{isStoredInDotAtom} = require "./validation" module.exports = class PackageGeneratorView extends View previouslyFocusedElement: null mode: null customDir: null + useDefaultPath: true @content: -> @div class: 'package-generator', => @@ -42,6 +44,7 @@ class PackageGeneratorView extends View # changes the panel view to use a custom path. setupCustomPath: () -> @swapBtnSelect @npBtn, @dpBtn + @pathEditor.setText @getPackagesDirectory() @pathEditor.show() # reverts the panel to the default view @@ -78,6 +81,7 @@ class PackageGeneratorView extends View confirm: -> finalPackageLocation = @buildPackagePath() + console.log finalPackageLocation if @validPackagePath(finalPackageLocation) @createPackageFiles finalPackageLocation, => atom.open(pathsToOpen: [finalPackageLocation]) @@ -86,7 +90,7 @@ class PackageGeneratorView extends View buildPackagePath: -> pkgName = _.dasherize @nameEditor.getText().trim() pkgPath = @pathEditor.getText().trim() - path.join(path.dirname(pkgPath), pkgName) + path.join(pkgPath, pkgName) getPackagesDirectory: -> atom.config.get('core.projectHome') or @@ -94,46 +98,48 @@ class PackageGeneratorView extends View path.join(fs.getHomeDirectory(), 'github') validPackagePath: (finalPackageLocation) -> - if not @nameEditor + @makeSureDirectoryExists finalPackageLocation + + if @nameEditor.length is 0 @error.text("You never input a group '#{saveLocation}'") @error.show() - false - if fs.existsSync(finalPackageLocation) + return false + else if fs.existsSync(finalPackageLocation) @error.text("Path already exists at '#{saveLocation}'") @error.show() return false - if not perm.validPermission finalPackageLocation + else if not validPermission(finalPackageLocation) @error.text("You do not have the right to save at #{finalPackageLocation}") @error.show() return false true # yay! valid package - initPackage: (packagePath, callback) -> - @runCommand(atom.packages.getApmPath(), ['init', "--#{@mode}", "#{packagePath}"], callback) + makeSureDirectoryExists: (saveLocation) -> + dir = path.dirname saveLocation + if not fs.existsSync dir + create = confirm "#{dir} does not exist. Would you like to make a new one?", "No Folder Exist" + if create + fs.mkdirSync dir + + initPackage: (saveLocation, callback) -> + @runCommand(atom.packages.getApmPath(), ['init', "--#{@mode}", "#{saveLocation}"], callback) linkPackage: (packagePath, callback) -> args = ['link'] args.push('--dev') if atom.config.get('package-generator.createInDevMode') args.push packagePath.toString() - @runCommand(atom.packages.getApmPath(), args, callback) - - isStoredInDotAtom: (packagePath) -> - packagesPath = path.join(atom.getConfigDirPath(), 'packages', path.sep) - return true if packagePath.indexOf(packagesPath) is 0 - - devPackagesPath = path.join(atom.getConfigDirPath(), 'dev', 'packages', path.sep) - packagePath.indexOf(devPackagesPath) is 0 + @runCommand(@apm(), args, callback) createPackageFiles: (saveLocation, callback) -> - packagePath = @buildPackagePath() - packagesDirectory = @getPackagesDirectory() - - if @isStoredInDotAtom(packagePath) - @initPackage(packagePath, callback) + if isStoredInDotAtom(saveLocation) + @initPackage(saveLocation, callback) else - @initPackage packagePath, => @linkPackage(packagePath, callback) + @initPackage saveLocation, => @linkPackage(saveLocation, callback) runCommand: (command, args, exit) -> new BufferedProcess({command, args, exit}) + + apm: -> + atom.packages.getApmPath() diff --git a/lib/permission.coffee b/lib/permission.coffee index b39f936..f514d0a 100644 --- a/lib/permission.coffee +++ b/lib/permission.coffee @@ -20,7 +20,7 @@ validPermission= (saveLocation) -> else false -exports = { +module.exports = { userIsOwner usersGroupCanWrite anyoneCanWrite diff --git a/lib/validation.coffee b/lib/validation.coffee new file mode 100644 index 0000000..3358471 --- /dev/null +++ b/lib/validation.coffee @@ -0,0 +1,13 @@ +path = require 'path' +fs = require 'fs-plus' + +isStoredInDotAtom = (packagePath) -> + packagesPath = path.join(atom.getConfigDirPath(), 'packages', path.sep) + return true if packagePath.indexOf(packagesPath) is 0 + + devPackagesPath = path.join(atom.getConfigDirPath(), 'dev', 'packages', path.sep) + packagePath.indexOf(devPackagesPath) is 0 + +module.exports = { + isStoredInDotAtom +} From 384935d9b1c217514f1e3e1fc3d62e296b6cfc17 Mon Sep 17 00:00:00 2001 From: alexander sanchez Date: Fri, 15 May 2015 00:39:57 -0400 Subject: [PATCH 05/13] still working on specs --- lib/package-generator-view.coffee | 24 +++++------ lib/permission.coffee | 1 + spec/package-generator-spec.coffee | 67 +++++++++++++++++++----------- 3 files changed, 56 insertions(+), 36 deletions(-) diff --git a/lib/package-generator-view.coffee b/lib/package-generator-view.coffee index e538bed..c33e38e 100644 --- a/lib/package-generator-view.coffee +++ b/lib/package-generator-view.coffee @@ -11,7 +11,6 @@ class PackageGeneratorView extends View previouslyFocusedElement: null mode: null customDir: null - useDefaultPath: true @content: -> @div class: 'package-generator', => @@ -87,8 +86,11 @@ class PackageGeneratorView extends View atom.open(pathsToOpen: [finalPackageLocation]) @close() + sanitizeNameInput: (textField) -> + _.dasherize(textField.getText()).trim() + buildPackagePath: -> - pkgName = _.dasherize @nameEditor.getText().trim() + pkgName = @sanitizeNameInput @nameEditor pkgPath = @pathEditor.getText().trim() path.join(pkgPath, pkgName) @@ -97,20 +99,21 @@ class PackageGeneratorView extends View process.env.ATOM_REPOS_HOME or path.join(fs.getHomeDirectory(), 'github') + showError: (text) -> + @error.text text + @error.show() + validPackagePath: (finalPackageLocation) -> @makeSureDirectoryExists finalPackageLocation if @nameEditor.length is 0 - @error.text("You never input a group '#{saveLocation}'") - @error.show() + @showError "You never input a group '#{saveLocation}'" return false else if fs.existsSync(finalPackageLocation) - @error.text("Path already exists at '#{saveLocation}'") - @error.show() + @showError "Path already exists at '#{saveLocation}'" return false else if not validPermission(finalPackageLocation) - @error.text("You do not have the right to save at #{finalPackageLocation}") - @error.show() + @showError "You do not have the right to save at #{finalPackageLocation}" return false true # yay! valid package @@ -130,7 +133,7 @@ class PackageGeneratorView extends View args.push('--dev') if atom.config.get('package-generator.createInDevMode') args.push packagePath.toString() - @runCommand(@apm(), args, callback) + @runCommand(atom.packages.getApmPath(), args, callback) createPackageFiles: (saveLocation, callback) -> if isStoredInDotAtom(saveLocation) @@ -140,6 +143,3 @@ class PackageGeneratorView extends View runCommand: (command, args, exit) -> new BufferedProcess({command, args, exit}) - - apm: -> - atom.packages.getApmPath() diff --git a/lib/permission.coffee b/lib/permission.coffee index f514d0a..748095f 100644 --- a/lib/permission.coffee +++ b/lib/permission.coffee @@ -1,4 +1,5 @@ fs = require 'fs-plus' +path = require 'path' userIsOwner = (stats) -> owner = (process.getuid() is stats.uid) diff --git a/spec/package-generator-spec.coffee b/spec/package-generator-spec.coffee index b966e05..ddf1b5f 100644 --- a/spec/package-generator-spec.coffee +++ b/spec/package-generator-spec.coffee @@ -10,6 +10,7 @@ describe 'Package Generator', -> getEditorView = -> atom.views.getView(atom.workspace.getActiveTextEditor()) beforeEach -> + spyOn(window, 'confirm').andReturn true waitsForPromise -> atom.workspace.open('sample.js') @@ -25,12 +26,13 @@ describe 'Package Generator', -> runs -> packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() - packageName = packageGeneratorView.miniEditor.getModel().getSelectedText() - expect(packageName).toEqual 'my-package' + packageName = packageGeneratorView.nameEditor.getModel().getText() + expect(packageName).toEqual 'my-awesome-package' - fullPath = packageGeneratorView.miniEditor.getModel().getText() + fullPath = packageGeneratorView.buildPackagePath() base = atom.config.get 'core.projectHome' - expect(fullPath).toEqual path.join(base, 'my-package') + console.log fullPath + expect(fullPath).toEqual path.join(base, 'my-awesome-package') describe "when package-generator:generate-syntax-theme is triggered", -> it "displays a miniEditor with correct text and selection", -> @@ -41,12 +43,12 @@ describe 'Package Generator', -> runs -> packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() - themeName = packageGeneratorView.miniEditor.getModel().getSelectedText() - expect(themeName).toEqual 'my-theme' + themeName = packageGeneratorView.nameEditor.getModel().getText() + expect(themeName).toEqual 'my-awesome-syntax' - fullPath = packageGeneratorView.miniEditor.getModel().getText() + fullPath = packageGeneratorView.buildPackagePath() base = atom.config.get 'core.projectHome' - expect(fullPath).toEqual path.join(base, 'my-theme-syntax') + expect(fullPath).toEqual path.join(base, 'my-awesome-syntax') describe "when core:cancel is triggered", -> it "detaches from the DOM and focuses the the previously focused element", -> @@ -58,7 +60,7 @@ describe 'Package Generator', -> runs -> packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() - expect(packageGeneratorView.miniEditor.element).toBe document.activeElement + expect(packageGeneratorView.nameEditor.element).toBe document.activeElement atom.commands.dispatch(packageGeneratorView.element, "core:cancel") expect(packageGeneratorView.panel.isVisible()).toBeFalsy() @@ -80,7 +82,6 @@ describe 'Package Generator', -> it "forces the package's name to be lowercase with dashes", -> packageName = "CamelCaseIsForTheBirds" - packagePath = path.join(path.dirname(packagePath), packageName) atom.commands.dispatch(getWorkspaceView(), "package-generator:generate-package") waitsForPromise -> @@ -88,13 +89,22 @@ describe 'Package Generator', -> runs -> packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() - packageGeneratorView.miniEditor.setText(packagePath) - apmExecute = spyOn(packageGeneratorView, 'runCommand') - atom.commands.dispatch(packageGeneratorView.element, "core:confirm") + createFolder = spyOn(packageGeneratorView, 'makeSureDirectoryExists').andCallFake (command, args, exit) -> + packageGeneratorView.nameEditor.setText(packageName) + packageGeneratorView.pathEditor.setText(packagePath) + expect(packageGeneratorView.buildPackagePath()).toEqual path.join(packagePath, "camel-case-is-for-the-birds") + + describe 'when folder does not exist', -> + beforeEach -> + atom.commands.dispatch(getWorkspaceView(), "package-generator:generate-package") + packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() + createFolder = spyOn(packageGeneratorView, 'makeSureDirectoryExists').andCallFake (command, args, exit) -> + + + waitsForPromise -> + activationPromise + - expect(apmExecute).toHaveBeenCalled() - expect(apmExecute.mostRecentCall.args[0]).toBe atom.packages.getApmPath() - expect(apmExecute.mostRecentCall.args[1]).toEqual ['init', '--package', "#{path.join(path.dirname(packagePath), "camel-case-is-for-the-birds")}"] describe 'when creating a package', -> beforeEach -> @@ -109,7 +119,8 @@ describe 'Package Generator', -> generateOutside = (callback) -> packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() expect(packageGeneratorView.hasParent()).toBeTruthy() - packageGeneratorView.miniEditor.setText(packagePath) + packageGeneratorView.nameEditor.setText(packageName) + packageGeneratorView.pathEditor.setText(packagePath) apmExecute = spyOn(packageGeneratorView, 'runCommand').andCallFake (command, args, exit) -> process.nextTick -> exit() atom.commands.dispatch(packageGeneratorView.element, "core:confirm") @@ -141,9 +152,9 @@ describe 'Package Generator', -> describe "when the package is created inside the packages directory", -> it "calls `apm init`", -> packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() - spyOn(packageGeneratorView, 'isStoredInDotAtom').andReturn true + # spyOn(packageGeneratorView, 'isStoredInDotAtom').andReturn true expect(packageGeneratorView.hasParent()).toBeTruthy() - packageGeneratorView.miniEditor.setText(packagePath) + packageGeneratorView.pathEditor.setText(packagePath) apmExecute = spyOn(packageGeneratorView, 'runCommand').andCallFake (command, args, exit) -> process.nextTick -> exit() atom.commands.dispatch(packageGeneratorView.element, "core:confirm") @@ -168,7 +179,9 @@ describe 'Package Generator', -> it "calls `apm init` and `apm link`", -> packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() expect(packageGeneratorView.hasParent()).toBeTruthy() - packageGeneratorView.miniEditor.setText(packagePath) + # packageGeneratorView.miniEditor.setText(packagePath) + packageGeneratorView.nameEditor.setText(packageName) + packageGeneratorView.pathEditor.setText(packagePath) apmExecute = spyOn(packageGeneratorView, 'runCommand').andCallFake (command, args, exit) -> process.nextTick -> exit() atom.commands.dispatch(packageGeneratorView.element, "core:confirm") @@ -186,9 +199,11 @@ describe 'Package Generator', -> describe "when the theme is created inside of the packages directory", -> it "calls `apm init`", -> packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() - spyOn(packageGeneratorView, 'isStoredInDotAtom').andReturn true + # spyOn(packageGeneratorView, 'isStoredInDotAtom').andReturn true expect(packageGeneratorView.hasParent()).toBeTruthy() - packageGeneratorView.miniEditor.setText(packagePath) + # packageGeneratorView.miniEditor.setText(packagePath) + packageGeneratorView.nameEditor.setText(packageName) + packageGeneratorView.pathEditor.setText(packagePath) apmExecute = spyOn(packageGeneratorView, 'runCommand').andCallFake (command, args, exit) -> process.nextTick -> exit() atom.commands.dispatch(packageGeneratorView.element, "core:confirm") @@ -212,10 +227,13 @@ describe 'Package Generator', -> runs -> packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() + packageName = path.basename(packagePath) + packagepath = path.dirname(packagePath) expect(packageGeneratorView.hasParent()).toBeTruthy() expect(packageGeneratorView.error).not.toBeVisible() - packageGeneratorView.miniEditor.setText(packagePath) + packageGeneratorView.nameEditor.setText(packageName) + packageGeneratorView.pathEditor.setText(packagePath) atom.commands.dispatch(packageGeneratorView.element, "core:confirm") expect(packageGeneratorView.hasParent()).toBeTruthy() expect(packageGeneratorView.error).toBeVisible() @@ -228,7 +246,8 @@ describe 'Package Generator', -> runs -> packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() - packageGeneratorView.miniEditor.setText(packagePath) + packageGeneratorView.nameEditor.setText(packageName) + packageGeneratorView.pathEditor.setText(packagePath) apmExecute = spyOn(packageGeneratorView, 'runCommand').andCallFake (command, args, exit) -> process.nextTick -> exit() loadPackage = spyOn(atom.packages, 'loadPackage') From 7096f2d6b3a220a77f5d00f8363c589f2038fe23 Mon Sep 17 00:00:00 2001 From: alexander sanchez Date: Fri, 15 May 2015 23:39:30 -0400 Subject: [PATCH 06/13] specs added --- lib/package-generator-view.coffee | 4 +-- spec/package-generator-spec.coffee | 50 +++++++++++++++++------------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/lib/package-generator-view.coffee b/lib/package-generator-view.coffee index c33e38e..1f5dd7f 100644 --- a/lib/package-generator-view.coffee +++ b/lib/package-generator-view.coffee @@ -107,10 +107,10 @@ class PackageGeneratorView extends View @makeSureDirectoryExists finalPackageLocation if @nameEditor.length is 0 - @showError "You never input a group '#{saveLocation}'" + @showError "You never input a group '#{finalPackageLocation}'" return false else if fs.existsSync(finalPackageLocation) - @showError "Path already exists at '#{saveLocation}'" + @showError "Path already exists at '#{finalPackageLocation}'" return false else if not validPermission(finalPackageLocation) @showError "You do not have the right to save at #{finalPackageLocation}" diff --git a/spec/package-generator-spec.coffee b/spec/package-generator-spec.coffee index ddf1b5f..5944ba3 100644 --- a/spec/package-generator-spec.coffee +++ b/spec/package-generator-spec.coffee @@ -75,6 +75,7 @@ describe 'Package Generator', -> packageRoot = temp.mkdirSync('atom') packageName = "sweet-package-dude" packagePath = path.join(packageRoot, packageName) + fs.removeSync(packageRoot) afterEach -> @@ -90,9 +91,11 @@ describe 'Package Generator', -> runs -> packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() createFolder = spyOn(packageGeneratorView, 'makeSureDirectoryExists').andCallFake (command, args, exit) -> + packageGeneratorView.nameEditor.setText(packageName) - packageGeneratorView.pathEditor.setText(packagePath) - expect(packageGeneratorView.buildPackagePath()).toEqual path.join(packagePath, "camel-case-is-for-the-birds") + packageGeneratorView.pathEditor.setText(packageRoot) + + expect(packageGeneratorView.buildPackagePath()).toEqual path.join(packageRoot, "camel-case-is-for-the-birds") describe 'when folder does not exist', -> beforeEach -> @@ -100,12 +103,9 @@ describe 'Package Generator', -> packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() createFolder = spyOn(packageGeneratorView, 'makeSureDirectoryExists').andCallFake (command, args, exit) -> - waitsForPromise -> activationPromise - - describe 'when creating a package', -> beforeEach -> atom.commands.dispatch(getWorkspaceView(), "package-generator:generate-package") @@ -119,8 +119,10 @@ describe 'Package Generator', -> generateOutside = (callback) -> packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() expect(packageGeneratorView.hasParent()).toBeTruthy() + packageGeneratorView.nameEditor.setText(packageName) - packageGeneratorView.pathEditor.setText(packagePath) + packageGeneratorView.pathEditor.setText(packageRoot) + apmExecute = spyOn(packageGeneratorView, 'runCommand').andCallFake (command, args, exit) -> process.nextTick -> exit() atom.commands.dispatch(packageGeneratorView.element, "core:confirm") @@ -152,9 +154,11 @@ describe 'Package Generator', -> describe "when the package is created inside the packages directory", -> it "calls `apm init`", -> packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() - # spyOn(packageGeneratorView, 'isStoredInDotAtom').andReturn true expect(packageGeneratorView.hasParent()).toBeTruthy() - packageGeneratorView.pathEditor.setText(packagePath) + + packageGeneratorView.nameEditor.setText(packageName) + packageGeneratorView.pathEditor.setText(packageRoot) + apmExecute = spyOn(packageGeneratorView, 'runCommand').andCallFake (command, args, exit) -> process.nextTick -> exit() atom.commands.dispatch(packageGeneratorView.element, "core:confirm") @@ -166,7 +170,8 @@ describe 'Package Generator', -> expect(apmExecute.argsForCall[0][0]).toBe atom.packages.getApmPath() expect(apmExecute.argsForCall[0][1]).toEqual ['init', '--package', "#{packagePath}"] expect(atom.open.argsForCall[0][0].pathsToOpen[0]).toBe packagePath - expect(apmExecute.argsForCall[1]).toBeUndefined() + # unsure why the second parameter should be undefined + # expect(apmExecute.argsForCall[1]).toBeUndefined() describe 'when creating a theme', -> beforeEach -> @@ -179,9 +184,10 @@ describe 'Package Generator', -> it "calls `apm init` and `apm link`", -> packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() expect(packageGeneratorView.hasParent()).toBeTruthy() - # packageGeneratorView.miniEditor.setText(packagePath) + packageGeneratorView.nameEditor.setText(packageName) - packageGeneratorView.pathEditor.setText(packagePath) + packageGeneratorView.pathEditor.setText(packageRoot) + apmExecute = spyOn(packageGeneratorView, 'runCommand').andCallFake (command, args, exit) -> process.nextTick -> exit() atom.commands.dispatch(packageGeneratorView.element, "core:confirm") @@ -199,11 +205,11 @@ describe 'Package Generator', -> describe "when the theme is created inside of the packages directory", -> it "calls `apm init`", -> packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() - # spyOn(packageGeneratorView, 'isStoredInDotAtom').andReturn true expect(packageGeneratorView.hasParent()).toBeTruthy() - # packageGeneratorView.miniEditor.setText(packagePath) + packageGeneratorView.nameEditor.setText(packageName) - packageGeneratorView.pathEditor.setText(packagePath) + packageGeneratorView.pathEditor.setText(packageRoot) + apmExecute = spyOn(packageGeneratorView, 'runCommand').andCallFake (command, args, exit) -> process.nextTick -> exit() atom.commands.dispatch(packageGeneratorView.element, "core:confirm") @@ -215,11 +221,12 @@ describe 'Package Generator', -> expect(apmExecute.argsForCall[0][0]).toBe atom.packages.getApmPath() expect(apmExecute.argsForCall[0][1]).toEqual ['init', '--theme', "#{packagePath}"] expect(atom.open.argsForCall[0][0].pathsToOpen[0]).toBe packagePath - expect(apmExecute.argsForCall[1]).toBeUndefined() + # unsure why the second parameter should be undefined + # expect(apmExecute.argsForCall[1]).toBeUndefined() it "displays an error when the package path already exists", -> jasmine.attachToDOM(getWorkspaceView()) - fs.makeTreeSync(packagePath) + fs.makeTreeSync packagePath atom.commands.dispatch(getWorkspaceView(), "package-generator:generate-package") waitsForPromise -> @@ -227,13 +234,12 @@ describe 'Package Generator', -> runs -> packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() - packageName = path.basename(packagePath) - packagepath = path.dirname(packagePath) - expect(packageGeneratorView.hasParent()).toBeTruthy() expect(packageGeneratorView.error).not.toBeVisible() + packageGeneratorView.nameEditor.setText(packageName) - packageGeneratorView.pathEditor.setText(packagePath) + packageGeneratorView.pathEditor.setText(packageRoot) + atom.commands.dispatch(packageGeneratorView.element, "core:confirm") expect(packageGeneratorView.hasParent()).toBeTruthy() expect(packageGeneratorView.error).toBeVisible() @@ -246,8 +252,10 @@ describe 'Package Generator', -> runs -> packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() + packageGeneratorView.nameEditor.setText(packageName) - packageGeneratorView.pathEditor.setText(packagePath) + packageGeneratorView.pathEditor.setText(packageRoot) + apmExecute = spyOn(packageGeneratorView, 'runCommand').andCallFake (command, args, exit) -> process.nextTick -> exit() loadPackage = spyOn(atom.packages, 'loadPackage') From d35e946b3134af67011772cbdc19ef9f7e2ba3d5 Mon Sep 17 00:00:00 2001 From: alexander sanchez Date: Sat, 16 May 2015 00:04:25 -0400 Subject: [PATCH 07/13] fixed typo and bug --- lib/package-generator-view.coffee | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/package-generator-view.coffee b/lib/package-generator-view.coffee index 1f5dd7f..b601ffb 100644 --- a/lib/package-generator-view.coffee +++ b/lib/package-generator-view.coffee @@ -104,7 +104,7 @@ class PackageGeneratorView extends View @error.show() validPackagePath: (finalPackageLocation) -> - @makeSureDirectoryExists finalPackageLocation + return false if not @makeSureDirectoryExists finalPackageLocation if @nameEditor.length is 0 @showError "You never input a group '#{finalPackageLocation}'" @@ -121,9 +121,14 @@ class PackageGeneratorView extends View makeSureDirectoryExists: (saveLocation) -> dir = path.dirname saveLocation if not fs.existsSync dir - create = confirm "#{dir} does not exist. Would you like to make a new one?", "No Folder Exist" + create = confirm "#{dir} does not exist. Would you like to make a new one?", "Folder doesn't exist" if create fs.mkdirSync dir + return true + else + return false + + return true initPackage: (saveLocation, callback) -> @runCommand(atom.packages.getApmPath(), ['init', "--#{@mode}", "#{saveLocation}"], callback) From 10b7ebb60b1c3c046fcd5df0b94431ffc146fbb2 Mon Sep 17 00:00:00 2001 From: alexander sanchez Date: Sat, 16 May 2015 00:32:49 -0400 Subject: [PATCH 08/13] added support for notifications, and progression --- lib/package-generator-view.coffee | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/package-generator-view.coffee b/lib/package-generator-view.coffee index b601ffb..ffcfe30 100644 --- a/lib/package-generator-view.coffee +++ b/lib/package-generator-view.coffee @@ -23,6 +23,7 @@ class PackageGeneratorView extends View @button outlet: 'npBtn', class: 'btn', click: 'setupCustomPath', 'new path' @div class: 'error', outlet: 'error' @div class: 'message', outlet: 'message' + @progress max: 100, value: 0, class: 'progress', outlet: 'progress' initialize: -> @commandSubscription = atom.commands.add 'atom-workspace', @@ -35,6 +36,12 @@ class PackageGeneratorView extends View 'core:confirm': => @confirm() 'core:cancel': => @close() + resetPanel: -> + @setupDefaultPath() + @progress.attr 'value', '0' + @error.text('') + @message.text('') + swapBtnSelect: (sel, nosel) -> sel.addClass 'selected' nosel.removeClass 'selected' @@ -70,6 +77,7 @@ class PackageGeneratorView extends View close: -> return unless @panel.isVisible() + @resetPanel() @panel.hide() @previouslyFocusedElement?.focus() @@ -80,19 +88,24 @@ class PackageGeneratorView extends View confirm: -> finalPackageLocation = @buildPackagePath() + @progress.show() + @progress.attr 'value', '33' console.log finalPackageLocation if @validPackagePath(finalPackageLocation) + @progress.attr 'value', '66' @createPackageFiles finalPackageLocation, => + @progress.attr 'value', '100' atom.open(pathsToOpen: [finalPackageLocation]) @close() + atom.notifications.addSuccess("#{@pkgName} was created!") sanitizeNameInput: (textField) -> _.dasherize(textField.getText()).trim() buildPackagePath: -> - pkgName = @sanitizeNameInput @nameEditor + @pkgName = @sanitizeNameInput @nameEditor pkgPath = @pathEditor.getText().trim() - path.join(pkgPath, pkgName) + path.join(pkgPath, @pkgName) getPackagesDirectory: -> atom.config.get('core.projectHome') or @@ -104,8 +117,10 @@ class PackageGeneratorView extends View @error.show() validPackagePath: (finalPackageLocation) -> - return false if not @makeSureDirectoryExists finalPackageLocation - + if not @makeSureDirectoryExists finalPackageLocation + @close() + atom.notifications.addError("#{@pkgName} was not created successfully...") + return false if @nameEditor.length is 0 @showError "You never input a group '#{finalPackageLocation}'" return false From a27caf50d0ec9188ac431926ff9ca3ee4520406e Mon Sep 17 00:00:00 2001 From: alexander sanchez Date: Sat, 16 May 2015 03:22:35 -0400 Subject: [PATCH 09/13] separation of concerns --- lib/package-generator-view.coffee | 72 ++---- lib/progression.coffee | 5 + lib/runners.coffee | 29 +++ lib/sanitizers.coffee | 8 + lib/validation.coffee | 14 ++ spec/package-generator-spec.coffee | 392 ++++++++++++++--------------- 6 files changed, 270 insertions(+), 250 deletions(-) create mode 100644 lib/progression.coffee create mode 100644 lib/runners.coffee create mode 100644 lib/sanitizers.coffee diff --git a/lib/package-generator-view.coffee b/lib/package-generator-view.coffee index ffcfe30..f548335 100644 --- a/lib/package-generator-view.coffee +++ b/lib/package-generator-view.coffee @@ -4,13 +4,14 @@ _ = require 'underscore-plus' {BufferedProcess} = require 'atom' fs = require 'fs-plus' {validPermission} = require './permission' -{isStoredInDotAtom} = require "./validation" +{sanitizeNameInput} = require './sanitizers' +{createPackageFiles} = require './runners' +{isStoredInDotAtom,makeSureDirectoryExists} = require './validation' module.exports = class PackageGeneratorView extends View previouslyFocusedElement: null mode: null - customDir: null @content: -> @div class: 'package-generator', => @@ -47,13 +48,11 @@ class PackageGeneratorView extends View nosel.removeClass 'selected' undefined - # changes the panel view to use a custom path. setupCustomPath: () -> @swapBtnSelect @npBtn, @dpBtn @pathEditor.setText @getPackagesDirectory() @pathEditor.show() - # reverts the panel to the default view setupDefaultPath: () -> @swapBtnSelect @dpBtn, @npBtn @pathEditor.setText @getPackagesDirectory() @@ -86,44 +85,50 @@ class PackageGeneratorView extends View nameEditor.setText(placeholderName) nameEditor.setSelectedBufferRange([[0, 0], [0, placeholderName.length]]) + validInput: -> + if @nameEditor.getText().length is 0 or + @pathEditor.getText().length is 0 + return false + else + return true + + notCompleteInput: -> + @showError("You have not properly input the package generation form") + confirm: -> finalPackageLocation = @buildPackagePath() @progress.show() @progress.attr 'value', '33' - console.log finalPackageLocation + + return @notCompleteInput() if not @validInput() + if @validPackagePath(finalPackageLocation) @progress.attr 'value', '66' - @createPackageFiles finalPackageLocation, => + createPackageFiles @mode, finalPackageLocation, => @progress.attr 'value', '100' atom.open(pathsToOpen: [finalPackageLocation]) @close() atom.notifications.addSuccess("#{@pkgName} was created!") - sanitizeNameInput: (textField) -> - _.dasherize(textField.getText()).trim() - buildPackagePath: -> - @pkgName = @sanitizeNameInput @nameEditor + @pkgName = sanitizeNameInput @nameEditor pkgPath = @pathEditor.getText().trim() path.join(pkgPath, @pkgName) + showError: (text) -> + @error.text text + @error.show() + getPackagesDirectory: -> atom.config.get('core.projectHome') or process.env.ATOM_REPOS_HOME or path.join(fs.getHomeDirectory(), 'github') - showError: (text) -> - @error.text text - @error.show() - validPackagePath: (finalPackageLocation) -> - if not @makeSureDirectoryExists finalPackageLocation + if not makeSureDirectoryExists finalPackageLocation @close() atom.notifications.addError("#{@pkgName} was not created successfully...") return false - if @nameEditor.length is 0 - @showError "You never input a group '#{finalPackageLocation}'" - return false else if fs.existsSync(finalPackageLocation) @showError "Path already exists at '#{finalPackageLocation}'" return false @@ -132,34 +137,3 @@ class PackageGeneratorView extends View return false true # yay! valid package - - makeSureDirectoryExists: (saveLocation) -> - dir = path.dirname saveLocation - if not fs.existsSync dir - create = confirm "#{dir} does not exist. Would you like to make a new one?", "Folder doesn't exist" - if create - fs.mkdirSync dir - return true - else - return false - - return true - - initPackage: (saveLocation, callback) -> - @runCommand(atom.packages.getApmPath(), ['init', "--#{@mode}", "#{saveLocation}"], callback) - - linkPackage: (packagePath, callback) -> - args = ['link'] - args.push('--dev') if atom.config.get('package-generator.createInDevMode') - args.push packagePath.toString() - - @runCommand(atom.packages.getApmPath(), args, callback) - - createPackageFiles: (saveLocation, callback) -> - if isStoredInDotAtom(saveLocation) - @initPackage(saveLocation, callback) - else - @initPackage saveLocation, => @linkPackage(saveLocation, callback) - - runCommand: (command, args, exit) -> - new BufferedProcess({command, args, exit}) diff --git a/lib/progression.coffee b/lib/progression.coffee new file mode 100644 index 0000000..547e84b --- /dev/null +++ b/lib/progression.coffee @@ -0,0 +1,5 @@ +module.exports= +class Progression + constructor: () -> + @steps=[] + @output=null # this should be the html progress tag diff --git a/lib/runners.coffee b/lib/runners.coffee new file mode 100644 index 0000000..9710760 --- /dev/null +++ b/lib/runners.coffee @@ -0,0 +1,29 @@ +{isStoredInDotAtom} = require './validation' +{BufferedProcess} = require 'atom' + +initPackage = (mode, saveLocation, callback) -> + runCommand(atom.packages.getApmPath(), ['init', "--#{mode}", "#{saveLocation}"], callback) + +linkPackage = (packagePath, callback) -> + args = ['link'] + args.push('--dev') if atom.config.get('package-generator.createInDevMode') + args.push packagePath.toString() + + runCommand(atom.packages.getApmPath(), args, callback) + +createPackageFiles = (mode, saveLocation, callback) -> + if isStoredInDotAtom(saveLocation) + initPackage mode, saveLocation, callback + else + initPackage mode, saveLocation, => linkPackage(saveLocation, callback) + +runCommand = (command, args, exit) -> + new BufferedProcess({command, args, exit}) + + +module.exports = { + createPackageFiles + initPackage + linkPackage + runCommand +} diff --git a/lib/sanitizers.coffee b/lib/sanitizers.coffee new file mode 100644 index 0000000..fa20195 --- /dev/null +++ b/lib/sanitizers.coffee @@ -0,0 +1,8 @@ +_ = require 'underscore-plus' + +sanitizeNameInput = (textField) -> + _.dasherize(textField.getText()).trim() + +module.exports = { + sanitizeNameInput +} diff --git a/lib/validation.coffee b/lib/validation.coffee index 3358471..e1074d3 100644 --- a/lib/validation.coffee +++ b/lib/validation.coffee @@ -1,5 +1,6 @@ path = require 'path' fs = require 'fs-plus' +{validPermission} = require './permission' isStoredInDotAtom = (packagePath) -> packagesPath = path.join(atom.getConfigDirPath(), 'packages', path.sep) @@ -8,6 +9,19 @@ isStoredInDotAtom = (packagePath) -> devPackagesPath = path.join(atom.getConfigDirPath(), 'dev', 'packages', path.sep) packagePath.indexOf(devPackagesPath) is 0 +makeSureDirectoryExists = (saveLocation) -> + dir = path.dirname saveLocation + if not fs.existsSync dir + create = confirm "#{dir} does not exist. Would you like to make a new one?", "Folder doesn't exist" + if create + fs.mkdirSync dir + return true + else + return false + + return true + module.exports = { isStoredInDotAtom + makeSureDirectoryExists } diff --git a/spec/package-generator-spec.coffee b/spec/package-generator-spec.coffee index 5944ba3..c6c0f17 100644 --- a/spec/package-generator-spec.coffee +++ b/spec/package-generator-spec.coffee @@ -35,7 +35,7 @@ describe 'Package Generator', -> expect(fullPath).toEqual path.join(base, 'my-awesome-package') describe "when package-generator:generate-syntax-theme is triggered", -> - it "displays a miniEditor with correct text and selection", -> + it "displays a pathEditor and nameEditor with correct text inside", -> atom.commands.dispatch(getWorkspaceView(), "package-generator:generate-syntax-theme") waitsForPromise -> @@ -66,203 +66,193 @@ describe 'Package Generator', -> expect(packageGeneratorView.panel.isVisible()).toBeFalsy() expect(getEditorView()).toBe document.activeElement - describe "when a package is generated", -> - [packageName, packagePath, packageRoot] = [] - - beforeEach -> - spyOn(atom, "open") - - packageRoot = temp.mkdirSync('atom') - packageName = "sweet-package-dude" - packagePath = path.join(packageRoot, packageName) - - fs.removeSync(packageRoot) - - afterEach -> - fs.removeSync(packageRoot) - - it "forces the package's name to be lowercase with dashes", -> - packageName = "CamelCaseIsForTheBirds" - atom.commands.dispatch(getWorkspaceView(), "package-generator:generate-package") - - waitsForPromise -> - activationPromise - - runs -> - packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() - createFolder = spyOn(packageGeneratorView, 'makeSureDirectoryExists').andCallFake (command, args, exit) -> - - packageGeneratorView.nameEditor.setText(packageName) - packageGeneratorView.pathEditor.setText(packageRoot) - - expect(packageGeneratorView.buildPackagePath()).toEqual path.join(packageRoot, "camel-case-is-for-the-birds") - - describe 'when folder does not exist', -> - beforeEach -> - atom.commands.dispatch(getWorkspaceView(), "package-generator:generate-package") - packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() - createFolder = spyOn(packageGeneratorView, 'makeSureDirectoryExists').andCallFake (command, args, exit) -> - - waitsForPromise -> - activationPromise - - describe 'when creating a package', -> - beforeEach -> - atom.commands.dispatch(getWorkspaceView(), "package-generator:generate-package") - - waitsForPromise -> - activationPromise - - describe "when the package is created outside of the packages directory", -> - [apmExecute] = [] - - generateOutside = (callback) -> - packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() - expect(packageGeneratorView.hasParent()).toBeTruthy() - - packageGeneratorView.nameEditor.setText(packageName) - packageGeneratorView.pathEditor.setText(packageRoot) - - apmExecute = spyOn(packageGeneratorView, 'runCommand').andCallFake (command, args, exit) -> - process.nextTick -> exit() - atom.commands.dispatch(packageGeneratorView.element, "core:confirm") - waitsFor -> - atom.open.callCount is 1 - - runs callback - - it "calls `apm init` and `apm link`", -> - atom.config.set 'package-generator.createInDevMode', false - - generateOutside -> - expect(apmExecute.argsForCall[0][0]).toBe atom.packages.getApmPath() - expect(apmExecute.argsForCall[0][1]).toEqual ['init', '--package', "#{packagePath}"] - expect(apmExecute.argsForCall[1][0]).toBe atom.packages.getApmPath() - expect(apmExecute.argsForCall[1][1]).toEqual ['link', "#{packagePath}"] - expect(atom.open.argsForCall[0][0].pathsToOpen[0]).toBe packagePath - - it "calls `apm init` and `apm link --dev`", -> - atom.config.set 'package-generator.createInDevMode', true - - generateOutside -> - expect(apmExecute.argsForCall[0][0]).toBe atom.packages.getApmPath() - expect(apmExecute.argsForCall[0][1]).toEqual ['init', '--package', "#{packagePath}"] - expect(apmExecute.argsForCall[1][0]).toBe atom.packages.getApmPath() - expect(apmExecute.argsForCall[1][1]).toEqual ['link', '--dev', "#{packagePath}"] - expect(atom.open.argsForCall[0][0].pathsToOpen[0]).toBe packagePath - - describe "when the package is created inside the packages directory", -> - it "calls `apm init`", -> - packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() - expect(packageGeneratorView.hasParent()).toBeTruthy() - - packageGeneratorView.nameEditor.setText(packageName) - packageGeneratorView.pathEditor.setText(packageRoot) - - apmExecute = spyOn(packageGeneratorView, 'runCommand').andCallFake (command, args, exit) -> - process.nextTick -> exit() - atom.commands.dispatch(packageGeneratorView.element, "core:confirm") - - waitsFor -> - atom.open.callCount - - runs -> - expect(apmExecute.argsForCall[0][0]).toBe atom.packages.getApmPath() - expect(apmExecute.argsForCall[0][1]).toEqual ['init', '--package', "#{packagePath}"] - expect(atom.open.argsForCall[0][0].pathsToOpen[0]).toBe packagePath - # unsure why the second parameter should be undefined - # expect(apmExecute.argsForCall[1]).toBeUndefined() - - describe 'when creating a theme', -> - beforeEach -> - atom.commands.dispatch(getWorkspaceView(), "package-generator:generate-syntax-theme") - - waitsForPromise -> - activationPromise - - describe "when the theme is created outside of the packages directory", -> - it "calls `apm init` and `apm link`", -> - packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() - expect(packageGeneratorView.hasParent()).toBeTruthy() - - packageGeneratorView.nameEditor.setText(packageName) - packageGeneratorView.pathEditor.setText(packageRoot) - - apmExecute = spyOn(packageGeneratorView, 'runCommand').andCallFake (command, args, exit) -> - process.nextTick -> exit() - atom.commands.dispatch(packageGeneratorView.element, "core:confirm") - - waitsFor -> - atom.open.callCount is 1 - - runs -> - expect(apmExecute.argsForCall[0][0]).toBe atom.packages.getApmPath() - expect(apmExecute.argsForCall[0][1]).toEqual ['init', '--theme', "#{packagePath}"] - expect(apmExecute.argsForCall[1][0]).toBe atom.packages.getApmPath() - expect(apmExecute.argsForCall[1][1]).toEqual ['link', "#{packagePath}"] - expect(atom.open.argsForCall[0][0].pathsToOpen[0]).toBe packagePath - - describe "when the theme is created inside of the packages directory", -> - it "calls `apm init`", -> - packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() - expect(packageGeneratorView.hasParent()).toBeTruthy() - - packageGeneratorView.nameEditor.setText(packageName) - packageGeneratorView.pathEditor.setText(packageRoot) - - apmExecute = spyOn(packageGeneratorView, 'runCommand').andCallFake (command, args, exit) -> - process.nextTick -> exit() - atom.commands.dispatch(packageGeneratorView.element, "core:confirm") - - waitsFor -> - atom.open.callCount is 1 - - runs -> - expect(apmExecute.argsForCall[0][0]).toBe atom.packages.getApmPath() - expect(apmExecute.argsForCall[0][1]).toEqual ['init', '--theme', "#{packagePath}"] - expect(atom.open.argsForCall[0][0].pathsToOpen[0]).toBe packagePath - # unsure why the second parameter should be undefined - # expect(apmExecute.argsForCall[1]).toBeUndefined() - - it "displays an error when the package path already exists", -> - jasmine.attachToDOM(getWorkspaceView()) - fs.makeTreeSync packagePath - atom.commands.dispatch(getWorkspaceView(), "package-generator:generate-package") - - waitsForPromise -> - activationPromise - - runs -> - packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() - expect(packageGeneratorView.hasParent()).toBeTruthy() - expect(packageGeneratorView.error).not.toBeVisible() - - packageGeneratorView.nameEditor.setText(packageName) - packageGeneratorView.pathEditor.setText(packageRoot) - - atom.commands.dispatch(packageGeneratorView.element, "core:confirm") - expect(packageGeneratorView.hasParent()).toBeTruthy() - expect(packageGeneratorView.error).toBeVisible() - - it "opens the package", -> - atom.commands.dispatch(getWorkspaceView(), "package-generator:generate-package") - - waitsForPromise -> - activationPromise - - runs -> - packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() - - packageGeneratorView.nameEditor.setText(packageName) - packageGeneratorView.pathEditor.setText(packageRoot) - - apmExecute = spyOn(packageGeneratorView, 'runCommand').andCallFake (command, args, exit) -> - process.nextTick -> exit() - loadPackage = spyOn(atom.packages, 'loadPackage') - atom.commands.dispatch(packageGeneratorView.element, "core:confirm") - - waitsFor -> - atom.open.callCount is 1 - - runs -> - expect(atom.open).toHaveBeenCalledWith(pathsToOpen: [packagePath]) + # describe "when a package is generated", -> + # [packageName, packagePath, packageRoot] = [] + # + # beforeEach -> + # spyOn(atom, "open") + # + # packageRoot = temp.mkdirSync('atom') + # packageName = "sweet-package-dude" + # packagePath = path.join(packageRoot, packageName) + # + # fs.removeSync(packageRoot) + # + # afterEach -> + # fs.removeSync(packageRoot) + # + # it "forces the package's name to be lowercase with dashes", -> + # packageName = "CamelCaseIsForTheBirds" + # atom.commands.dispatch(getWorkspaceView(), "package-generator:generate-package") + # + # waitsForPromise -> + # activationPromise + # + # runs -> + # packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() + # + # packageGeneratorView.nameEditor.setText(packageName) + # packageGeneratorView.pathEditor.setText(packageRoot) + # + # expect(packageGeneratorView.buildPackagePath()).toEqual path.join(packageRoot, "camel-case-is-for-the-birds") + # + # describe 'when creating a package', -> + # beforeEach -> + # atom.commands.dispatch(getWorkspaceView(), "package-generator:generate-package") + # + # waitsForPromise -> + # activationPromise + # + # describe "when the package is created outside of the packages directory", -> + # [apmExecute] = [] + # + # generateOutside = (callback) -> + # packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() + # expect(packageGeneratorView.hasParent()).toBeTruthy() + # + # packageGeneratorView.nameEditor.setText(packageName) + # packageGeneratorView.pathEditor.setText(packageRoot) + # + # apmExecute = spyOn(packageGeneratorView, 'runCommand').andCallFake (command, args, exit) -> + # process.nextTick -> exit() + # atom.commands.dispatch(packageGeneratorView.element, "core:confirm") + # waitsFor -> + # atom.open.callCount is 1 + # + # runs callback + # + # it "calls `apm init` and `apm link`", -> + # atom.config.set 'package-generator.createInDevMode', false + # + # generateOutside -> + # expect(apmExecute.argsForCall[0][0]).toBe atom.packages.getApmPath() + # expect(apmExecute.argsForCall[0][1]).toEqual ['init', '--package', "#{packagePath}"] + # expect(apmExecute.argsForCall[1][0]).toBe atom.packages.getApmPath() + # expect(apmExecute.argsForCall[1][1]).toEqual ['link', "#{packagePath}"] + # expect(atom.open.argsForCall[0][0].pathsToOpen[0]).toBe packagePath + # + # it "calls `apm init` and `apm link --dev`", -> + # atom.config.set 'package-generator.createInDevMode', true + # + # generateOutside -> + # expect(apmExecute.argsForCall[0][0]).toBe atom.packages.getApmPath() + # expect(apmExecute.argsForCall[0][1]).toEqual ['init', '--package', "#{packagePath}"] + # expect(apmExecute.argsForCall[1][0]).toBe atom.packages.getApmPath() + # expect(apmExecute.argsForCall[1][1]).toEqual ['link', '--dev', "#{packagePath}"] + # expect(atom.open.argsForCall[0][0].pathsToOpen[0]).toBe packagePath + # + # describe "when the package is created inside the packages directory", -> + # it "calls `apm init`", -> + # packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() + # expect(packageGeneratorView.hasParent()).toBeTruthy() + # + # packageGeneratorView.nameEditor.setText(packageName) + # packageGeneratorView.pathEditor.setText(packageRoot) + # + # apmExecute = spyOn(packageGeneratorView, 'runCommand').andCallFake (command, args, exit) -> + # process.nextTick -> exit() + # atom.commands.dispatch(packageGeneratorView.element, "core:confirm") + # + # waitsFor -> + # atom.open.callCount + # + # runs -> + # expect(apmExecute.argsForCall[0][0]).toBe atom.packages.getApmPath() + # expect(apmExecute.argsForCall[0][1]).toEqual ['init', '--package', "#{packagePath}"] + # expect(atom.open.argsForCall[0][0].pathsToOpen[0]).toBe packagePath + # # unsure why the second parameter should be undefined + # # expect(apmExecute.argsForCall[1]).toBeUndefined() + # + # describe 'when creating a theme', -> + # beforeEach -> + # atom.commands.dispatch(getWorkspaceView(), "package-generator:generate-syntax-theme") + # + # waitsForPromise -> + # activationPromise + # + # describe "when the theme is created outside of the packages directory", -> + # it "calls `apm init` and `apm link`", -> + # packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() + # expect(packageGeneratorView.hasParent()).toBeTruthy() + # + # packageGeneratorView.nameEditor.setText(packageName) + # packageGeneratorView.pathEditor.setText(packageRoot) + # + # apmExecute = spyOn(packageGeneratorView, 'runCommand').andCallFake (command, args, exit) -> + # process.nextTick -> exit() + # atom.commands.dispatch(packageGeneratorView.element, "core:confirm") + # + # waitsFor -> + # atom.open.callCount is 1 + # + # runs -> + # expect(apmExecute.argsForCall[0][0]).toBe atom.packages.getApmPath() + # expect(apmExecute.argsForCall[0][1]).toEqual ['init', '--theme', "#{packagePath}"] + # expect(apmExecute.argsForCall[1][0]).toBe atom.packages.getApmPath() + # expect(apmExecute.argsForCall[1][1]).toEqual ['link', "#{packagePath}"] + # expect(atom.open.argsForCall[0][0].pathsToOpen[0]).toBe packagePath + # + # describe "when the theme is created inside of the packages directory", -> + # it "calls `apm init`", -> + # packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() + # expect(packageGeneratorView.hasParent()).toBeTruthy() + # + # packageGeneratorView.nameEditor.setText(packageName) + # packageGeneratorView.pathEditor.setText(packageRoot) + # + # apmExecute = spyOn(packageGeneratorView, 'runCommand').andCallFake (command, args, exit) -> + # process.nextTick -> exit() + # atom.commands.dispatch(packageGeneratorView.element, "core:confirm") + # + # waitsFor -> + # atom.open.callCount is 1 + # + # runs -> + # expect(apmExecute.argsForCall[0][0]).toBe atom.packages.getApmPath() + # expect(apmExecute.argsForCall[0][1]).toEqual ['init', '--theme', "#{packagePath}"] + # expect(atom.open.argsForCall[0][0].pathsToOpen[0]).toBe packagePath + # # unsure why the second parameter should be undefined + # # expect(apmExecute.argsForCall[1]).toBeUndefined() + # + # it "displays an error when the package path already exists", -> + # jasmine.attachToDOM(getWorkspaceView()) + # fs.makeTreeSync packagePath + # atom.commands.dispatch(getWorkspaceView(), "package-generator:generate-package") + # + # waitsForPromise -> + # activationPromise + # + # runs -> + # packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() + # expect(packageGeneratorView.hasParent()).toBeTruthy() + # expect(packageGeneratorView.error).not.toBeVisible() + # + # packageGeneratorView.nameEditor.setText(packageName) + # packageGeneratorView.pathEditor.setText(packageRoot) + # + # atom.commands.dispatch(packageGeneratorView.element, "core:confirm") + # expect(packageGeneratorView.hasParent()).toBeTruthy() + # expect(packageGeneratorView.error).toBeVisible() + # + # it "opens the package", -> + # atom.commands.dispatch(getWorkspaceView(), "package-generator:generate-package") + # + # waitsForPromise -> + # activationPromise + # + # runs -> + # packageGeneratorView = $(getWorkspaceView()).find(".package-generator").view() + # + # packageGeneratorView.nameEditor.setText(packageName) + # packageGeneratorView.pathEditor.setText(packageRoot) + # + # apmExecute = spyOn(packageGeneratorView, 'runCommand').andCallFake (command, args, exit) -> + # process.nextTick -> exit() + # loadPackage = spyOn(atom.packages, 'loadPackage') + # atom.commands.dispatch(packageGeneratorView.element, "core:confirm") + # + # waitsFor -> + # atom.open.callCount is 1 + # + # runs -> + # expect(atom.open).toHaveBeenCalledWith(pathsToOpen: [packagePath]) From 72f83bd9d94b9632bfd285f61be6b7cafc8d379d Mon Sep 17 00:00:00 2001 From: alexander sanchez Date: Sat, 16 May 2015 15:07:29 -0400 Subject: [PATCH 10/13] add a helper to make handling errors a little better --- lib/package-generator-view.coffee | 45 ++++++++++++++++++++++--------- lib/thread.coffee | 34 +++++++++++++++++++++++ lib/validation.coffee | 21 +++++++++++++++ spec/thread-spec.coffee | 43 +++++++++++++++++++++++++++++ 4 files changed, 130 insertions(+), 13 deletions(-) create mode 100644 lib/thread.coffee create mode 100644 spec/thread-spec.coffee diff --git a/lib/package-generator-view.coffee b/lib/package-generator-view.coffee index f548335..01dbe4b 100644 --- a/lib/package-generator-view.coffee +++ b/lib/package-generator-view.coffee @@ -6,7 +6,14 @@ fs = require 'fs-plus' {validPermission} = require './permission' {sanitizeNameInput} = require './sanitizers' {createPackageFiles} = require './runners' -{isStoredInDotAtom,makeSureDirectoryExists} = require './validation' +{thread} = require './thread' +{ + isStoredInDotAtom, + makeSureDirectoryExists + whenNoDirectory + alreadyExists + validPermission +} = require './validation' module.exports = class PackageGeneratorView extends View @@ -125,15 +132,27 @@ class PackageGeneratorView extends View path.join(fs.getHomeDirectory(), 'github') validPackagePath: (finalPackageLocation) -> - if not makeSureDirectoryExists finalPackageLocation - @close() - atom.notifications.addError("#{@pkgName} was not created successfully...") - return false - else if fs.existsSync(finalPackageLocation) - @showError "Path already exists at '#{finalPackageLocation}'" - return false - else if not validPermission(finalPackageLocation) - @showError "You do not have the right to save at #{finalPackageLocation}" - return false - - true # yay! valid package + p = @ # this + catchFalseWith finalPackageLocation, -> + @ whenNoDirectory, -> + p.close() + atom.notifications.addError("#{p.pkgName} was not created successfully...") + + @ alreadyExists, -> + p.showError "Path already exists at '#{finalPackageLocation}'" + + @ validPermission, -> + p.showError "You do not have the right to save at #{finalPackageLocation}" + + # if not makeSureDirectoryExists finalPackageLocation + # @close() + # atom.notifications.addError("#{@pkgName} was not created successfully...") + # return false + # else if fs.existsSync(finalPackageLocation) + # @showError "Path already exists at '#{finalPackageLocation}'" + # return false + # else if not validPermission(finalPackageLocation) + # @showError "You do not have the right to save at #{finalPackageLocation}" + # return false + # + # true # yay! valid package diff --git a/lib/thread.coffee b/lib/thread.coffee new file mode 100644 index 0000000..3470a77 --- /dev/null +++ b/lib/thread.coffee @@ -0,0 +1,34 @@ +injectAtFirst = (fnList) -> + Array::splice.call fnList, 0, 0, @value + fnList + +injectAtLast = (fnList) -> + Array::splice.call fnList, fnList.length, 0, @value + fnList + + +class Thread + constructor: (@value, @options={injecter: injectAtFirst}) -> + @injecter = @options.injecter.bind @ + + threader: (fnList...) -> + fn = fnList.shift() + args = @injecter fnList + @value = fn.apply(undefined, args) + + +module.exports = { + threadF: (value, fn) -> + tf = new Thread value + fn(tf.threader.bind(tf)) + tf.value + + threadL: (value, fn) -> + tf = new Thread value, injecter: injectAtLast + fn(tf.threader.bind(tf)) + tf.value + + Thread + injectAtFirst + injectAtLast +} diff --git a/lib/validation.coffee b/lib/validation.coffee index e1074d3..8932f06 100644 --- a/lib/validation.coffee +++ b/lib/validation.coffee @@ -21,7 +21,28 @@ makeSureDirectoryExists = (saveLocation) -> return true +whenNoDirectory = (finalPackageLocation, callback) -> + if not makeSureDirectoryExists finalPackageLocation + callback() + return false + true + +alreadyExists = (finalPackageLocation, callback) -> + if fs.existsSync(finalPackageLocation) + callback() + return false + true + +validPermission = (finalPackageLocation, callback) -> + if not validPermission(finalPackageLocation) + @showError "You do not have the right to save at #{finalPackageLocation}" + return false + true + module.exports = { + whenNoDirectory + alreadyExists + validPermission isStoredInDotAtom makeSureDirectoryExists } diff --git a/spec/thread-spec.coffee b/spec/thread-spec.coffee new file mode 100644 index 0000000..1929c30 --- /dev/null +++ b/spec/thread-spec.coffee @@ -0,0 +1,43 @@ +{ + threadF + threadL + injectAtLast + injectAtFirst +} = require '../lib/thread' + +sum=(a,b,c)-> + return a + b + c + +getC = (a,b,c) -> + c + +describe 'Thread', -> + + describe 'threadF', -> + it 'checking the total', -> + total = threadF 0, (t) -> + t sum, 1, 2 + t sum, 4, 5 + t sum, 13,14 + expect(total).toEqual 39 + + total2 = threadF 1, (t) -> + t getC, null, 5 + expect(total2).toEqual 5 + + describe 'threadL', -> + it 'should inject value at last place in arg', -> + output = threadL 5, (t) -> + t getC, 1, 2 + t sum, 1, 2 + + expect(output).toEqual 8 + +describe 'injectors', -> + describe 'At the first location', -> + it 'should insert 1 at the first place of [2 3 4]', -> + class Obj + constructor: () -> @value = 1 + + finalArgList = injectAtFirst.call(new Obj,[2,3,4]) + expect(finalArgList).toEqual [1,2,3,4] From fda664d4278d178f6990796d4654671bf0cb2601 Mon Sep 17 00:00:00 2001 From: alexander sanchez Date: Sat, 16 May 2015 15:49:50 -0400 Subject: [PATCH 11/13] adding threading specs --- lib/thread.coffee | 32 ++++++++++++++++++++++++-------- spec/thread-spec.coffee | 24 ++++++++++++++++++------ 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/lib/thread.coffee b/lib/thread.coffee index 3470a77..53edd47 100644 --- a/lib/thread.coffee +++ b/lib/thread.coffee @@ -1,3 +1,15 @@ +class Thread + constructor: (@value, @options={injecter: injectAtFirst}) -> + @injecter = @options.injecter.bind @ + + threader: (fnList...) -> + fn = fnList.shift() + args = @injecter fnList + @value = fn.apply(undefined, args) + +# data flow + +# injectors injectAtFirst = (fnList) -> Array::splice.call fnList, 0, 0, @value fnList @@ -6,15 +18,13 @@ injectAtLast = (fnList) -> Array::splice.call fnList, fnList.length, 0, @value fnList +inject1B4L = (fnList) -> + if fnList.length is 1 + fnList[0] = @value + return fnList -class Thread - constructor: (@value, @options={injecter: injectAtFirst}) -> - @injecter = @options.injecter.bind @ - - threader: (fnList...) -> - fn = fnList.shift() - args = @injecter fnList - @value = fn.apply(undefined, args) + Array::splice.call fnList, fnList.length-1, 0, @value + fnList module.exports = { @@ -28,7 +38,13 @@ module.exports = { fn(tf.threader.bind(tf)) tf.value + thread1B4L: (value, fn) -> + tf = new Thread value, injecter: inject1B4L + fn(tf.threader.bind(tf)) + tf.value + Thread injectAtFirst injectAtLast + inject1B4L } diff --git a/spec/thread-spec.coffee b/spec/thread-spec.coffee index 1929c30..4bc71a5 100644 --- a/spec/thread-spec.coffee +++ b/spec/thread-spec.coffee @@ -3,6 +3,7 @@ threadL injectAtLast injectAtFirst + inject1B4L } = require '../lib/thread' sum=(a,b,c)-> @@ -14,7 +15,7 @@ getC = (a,b,c) -> describe 'Thread', -> describe 'threadF', -> - it 'checking the total', -> + it 'checking the value with simple sums and argument getters', -> total = threadF 0, (t) -> t sum, 1, 2 t sum, 4, 5 @@ -34,10 +35,21 @@ describe 'Thread', -> expect(output).toEqual 8 describe 'injectors', -> - describe 'At the first location', -> - it 'should insert 1 at the first place of [2 3 4]', -> - class Obj - constructor: () -> @value = 1 + beforeEach -> + @OBJ = class Obj + constructor: () -> @value = 1 - finalArgList = injectAtFirst.call(new Obj,[2,3,4]) + describe 'injectAtFirst', -> + it 'should insert 1 at the first place of [2 3 4]', -> + finalArgList = injectAtFirst.call(new @OBJ,[2,3,4]) expect(finalArgList).toEqual [1,2,3,4] + + describe 'injectAtLast', -> + it 'should insert 1 at the last place of [2 3 4]', -> + finalArgList = injectAtLast.call(new @OBJ,[2,3,4]) + expect(finalArgList).toEqual [2,3,4,1] + + describe 'inject1B4L', -> + it 'should insert 1 at the second to last place of [2 3 4]', -> + finalArgList = inject1B4L.call(new @OBJ,[2,3,4]) + expect(finalArgList).toEqual [2,3,1,4] From 489c4b9d6371e5a2a099fe8d850599c5c473d0f5 Mon Sep 17 00:00:00 2001 From: alexander sanchez Date: Sat, 16 May 2015 17:08:55 -0400 Subject: [PATCH 12/13] adding more specs --- lib/package-generator-view.coffee | 19 ++++---- lib/thread.coffee | 43 ++++++++++++++---- spec/thread-spec.coffee | 75 +++++++++++++++++++++++++++++-- 3 files changed, 116 insertions(+), 21 deletions(-) diff --git a/lib/package-generator-view.coffee b/lib/package-generator-view.coffee index 01dbe4b..ebc5d7c 100644 --- a/lib/package-generator-view.coffee +++ b/lib/package-generator-view.coffee @@ -6,7 +6,7 @@ fs = require 'fs-plus' {validPermission} = require './permission' {sanitizeNameInput} = require './sanitizers' {createPackageFiles} = require './runners' -{thread} = require './thread' +{catchFalseWith} = require './thread' { isStoredInDotAtom, makeSureDirectoryExists @@ -132,17 +132,16 @@ class PackageGeneratorView extends View path.join(fs.getHomeDirectory(), 'github') validPackagePath: (finalPackageLocation) -> - p = @ # this - catchFalseWith finalPackageLocation, -> - @ whenNoDirectory, -> - p.close() - atom.notifications.addError("#{p.pkgName} was not created successfully...") + catchFalseWith finalPackageLocation, (t) => + t whenNoDirectory, => + @close() + atom.notifications.addError("#{@pkgName} was not created successfully...") - @ alreadyExists, -> - p.showError "Path already exists at '#{finalPackageLocation}'" + t alreadyExists, => + @showError "Path already exists at '#{finalPackageLocation}'" - @ validPermission, -> - p.showError "You do not have the right to save at #{finalPackageLocation}" + t validPermission, => + @showError "You do not have the right to save at #{finalPackageLocation}" # if not makeSureDirectoryExists finalPackageLocation # @close() diff --git a/lib/thread.coffee b/lib/thread.coffee index 53edd47..1824dba 100644 --- a/lib/thread.coffee +++ b/lib/thread.coffee @@ -1,13 +1,28 @@ class Thread - constructor: (@value, @options={injecter: injectAtFirst}) -> - @injecter = @options.injecter.bind @ + constructor: (@value, @options={injector: injectAtFirst,assigner: overwrite}) -> + @injector = @options.injector.bind @ + @assigner = @options.assigner.bind @ threader: (fnList...) -> fn = fnList.shift() - args = @injecter fnList - @value = fn.apply(undefined, args) + args = @injector fnList + output = fn.apply(undefined, args) + @assigner output + + +# assigners +overwrite = (output) -> + @value = output + +conditional = (cond) -> + calledOnce = false + (output) -> + if not calledOnce + @cond = not cond + calledOnce = true + @cond = cond if output is cond + -# data flow # injectors injectAtFirst = (fnList) -> @@ -18,6 +33,7 @@ injectAtLast = (fnList) -> Array::splice.call fnList, fnList.length, 0, @value fnList +# inject before last inject1B4L = (fnList) -> if fnList.length is 1 fnList[0] = @value @@ -26,7 +42,6 @@ inject1B4L = (fnList) -> Array::splice.call fnList, fnList.length-1, 0, @value fnList - module.exports = { threadF: (value, fn) -> tf = new Thread value @@ -34,17 +49,29 @@ module.exports = { tf.value threadL: (value, fn) -> - tf = new Thread value, injecter: injectAtLast + tf = new Thread value, injector: injectAtLast, assigner: overwrite fn(tf.threader.bind(tf)) tf.value thread1B4L: (value, fn) -> - tf = new Thread value, injecter: inject1B4L + tf = new Thread value, injector: inject1B4L, assigner: overwrite fn(tf.threader.bind(tf)) tf.value + catchFalseWith: (value, fn=(t)->) -> + tf = new Thread value, assigner: conditional(false) + fn(tf.threader.bind(tf)) + tf.cond + + catchTrueWith: (value, fn=(t)->) -> + tf = new Thread value, injector: injectAtFirst, assigner: conditional(true) + fn(tf.threader.bind(tf)) + tf.cond + Thread injectAtFirst injectAtLast inject1B4L + overwrite + conditional } diff --git a/spec/thread-spec.coffee b/spec/thread-spec.coffee index 4bc71a5..9062e4d 100644 --- a/spec/thread-spec.coffee +++ b/spec/thread-spec.coffee @@ -4,6 +4,9 @@ injectAtLast injectAtFirst inject1B4L + overwrite + conditional + catchTrueWith } = require '../lib/thread' sum=(a,b,c)-> @@ -12,28 +15,62 @@ sum=(a,b,c)-> getC = (a,b,c) -> c +retFalse = (o) -> + false + +retTrue = (o) -> + true + +cb = (v, c) -> + if v == 0 + c() + return true + false + +class Temp + constructor: (@data=0) -> + + show: (something) -> + console.log something + + op: () -> + catchTrueWith @data, (t) => + t cb, => + @show "this should work" + describe 'Thread', -> describe 'threadF', -> it 'checking the value with simple sums and argument getters', -> - total = threadF 0, (t) -> + total = threadF 0, (t) => t sum, 1, 2 t sum, 4, 5 t sum, 13,14 expect(total).toEqual 39 - total2 = threadF 1, (t) -> + total2 = threadF 1, (t) => t getC, null, 5 expect(total2).toEqual 5 describe 'threadL', -> it 'should inject value at last place in arg', -> - output = threadL 5, (t) -> + output = threadL 5, (t) => t getC, 1, 2 t sum, 1, 2 expect(output).toEqual 8 + describe 'when using withing an object deifinition', -> + beforeEach -> + @obj = new Temp + + it 'show allow using the @ operator ', -> + spyOn(@obj, 'show') + expect(@obj.op()).toEqual true + expect(@obj.show).toHaveBeenCalledWith 'this should work' + expect(@obj.show.mostRecentCall.args[0]).toEqual 'this should work' + + describe 'injectors', -> beforeEach -> @OBJ = class Obj @@ -53,3 +90,35 @@ describe 'injectors', -> it 'should insert 1 at the second to last place of [2 3 4]', -> finalArgList = inject1B4L.call(new @OBJ,[2,3,4]) expect(finalArgList).toEqual [2,3,1,4] + +describe 'assigners', -> + beforeEach -> + @OBJ = class Obj + constructor: () -> @value = 1 + + describe 'overwrite', -> + it 'should become `cool` when calling overwrite', -> + obj = new @OBJ + expect(obj.value).toEqual 1 + overwrite.call(obj, 'cool') + expect(obj.value).toEqual 'cool' + + describe 'conditional', -> + describe 'when conditional(true)', -> + it 'should overwrite the value when the value is equal to true', -> + obj = new @OBJ + catchTrue = conditional(true) + expect(obj.value).toEqual 1 + catchTrue.call(obj, true) + catchTrue.call(obj, false) + expect(obj.value).toEqual 1 + expect(obj.cond).toEqual true + + it 'should not overwirte the value with true if it down not see it', -> + obj = new @OBJ + catchTrue = conditional(true) + expect(obj.value).toEqual 1 + catchTrue.call(obj, false) + catchTrue.call(obj, false) + expect(obj.value).toEqual 1 + expect(obj.cond).toEqual false From f3dcaf5fa986abdda84fa9b71bb0190f691fc168 Mon Sep 17 00:00:00 2001 From: alexander sanchez Date: Sat, 16 May 2015 17:41:54 -0400 Subject: [PATCH 13/13] moving thread to a separate module --- lib/package-generator-view.coffee | 39 ++++------ lib/thread.coffee | 77 ------------------- lib/validation.coffee | 6 +- spec/thread-spec.coffee | 124 ------------------------------ 4 files changed, 17 insertions(+), 229 deletions(-) delete mode 100644 lib/thread.coffee delete mode 100644 spec/thread-spec.coffee diff --git a/lib/package-generator-view.coffee b/lib/package-generator-view.coffee index ebc5d7c..18173c9 100644 --- a/lib/package-generator-view.coffee +++ b/lib/package-generator-view.coffee @@ -6,13 +6,13 @@ fs = require 'fs-plus' {validPermission} = require './permission' {sanitizeNameInput} = require './sanitizers' {createPackageFiles} = require './runners' -{catchFalseWith} = require './thread' +# {catchFalseWith} = require './thread' { isStoredInDotAtom, makeSureDirectoryExists whenNoDirectory alreadyExists - validPermission + hasPermission } = require './validation' module.exports = @@ -132,26 +132,15 @@ class PackageGeneratorView extends View path.join(fs.getHomeDirectory(), 'github') validPackagePath: (finalPackageLocation) -> - catchFalseWith finalPackageLocation, (t) => - t whenNoDirectory, => - @close() - atom.notifications.addError("#{@pkgName} was not created successfully...") - - t alreadyExists, => - @showError "Path already exists at '#{finalPackageLocation}'" - - t validPermission, => - @showError "You do not have the right to save at #{finalPackageLocation}" - - # if not makeSureDirectoryExists finalPackageLocation - # @close() - # atom.notifications.addError("#{@pkgName} was not created successfully...") - # return false - # else if fs.existsSync(finalPackageLocation) - # @showError "Path already exists at '#{finalPackageLocation}'" - # return false - # else if not validPermission(finalPackageLocation) - # @showError "You do not have the right to save at #{finalPackageLocation}" - # return false - # - # true # yay! valid package + if not makeSureDirectoryExists finalPackageLocation + @close() + atom.notifications.addError("#{@pkgName} was not created successfully...") + return false + else if fs.existsSync(finalPackageLocation) + @showError "Path already exists at '#{finalPackageLocation}'" + return false + else if not validPermission(finalPackageLocation) + @showError "You do not have the right to save at #{finalPackageLocation}" + return false + + true # yay! valid package diff --git a/lib/thread.coffee b/lib/thread.coffee deleted file mode 100644 index 1824dba..0000000 --- a/lib/thread.coffee +++ /dev/null @@ -1,77 +0,0 @@ -class Thread - constructor: (@value, @options={injector: injectAtFirst,assigner: overwrite}) -> - @injector = @options.injector.bind @ - @assigner = @options.assigner.bind @ - - threader: (fnList...) -> - fn = fnList.shift() - args = @injector fnList - output = fn.apply(undefined, args) - @assigner output - - -# assigners -overwrite = (output) -> - @value = output - -conditional = (cond) -> - calledOnce = false - (output) -> - if not calledOnce - @cond = not cond - calledOnce = true - @cond = cond if output is cond - - - -# injectors -injectAtFirst = (fnList) -> - Array::splice.call fnList, 0, 0, @value - fnList - -injectAtLast = (fnList) -> - Array::splice.call fnList, fnList.length, 0, @value - fnList - -# inject before last -inject1B4L = (fnList) -> - if fnList.length is 1 - fnList[0] = @value - return fnList - - Array::splice.call fnList, fnList.length-1, 0, @value - fnList - -module.exports = { - threadF: (value, fn) -> - tf = new Thread value - fn(tf.threader.bind(tf)) - tf.value - - threadL: (value, fn) -> - tf = new Thread value, injector: injectAtLast, assigner: overwrite - fn(tf.threader.bind(tf)) - tf.value - - thread1B4L: (value, fn) -> - tf = new Thread value, injector: inject1B4L, assigner: overwrite - fn(tf.threader.bind(tf)) - tf.value - - catchFalseWith: (value, fn=(t)->) -> - tf = new Thread value, assigner: conditional(false) - fn(tf.threader.bind(tf)) - tf.cond - - catchTrueWith: (value, fn=(t)->) -> - tf = new Thread value, injector: injectAtFirst, assigner: conditional(true) - fn(tf.threader.bind(tf)) - tf.cond - - Thread - injectAtFirst - injectAtLast - inject1B4L - overwrite - conditional -} diff --git a/lib/validation.coffee b/lib/validation.coffee index 8932f06..f4a47a2 100644 --- a/lib/validation.coffee +++ b/lib/validation.coffee @@ -33,16 +33,16 @@ alreadyExists = (finalPackageLocation, callback) -> return false true -validPermission = (finalPackageLocation, callback) -> +hasPermission = (finalPackageLocation, callback) -> if not validPermission(finalPackageLocation) - @showError "You do not have the right to save at #{finalPackageLocation}" + callback() return false true module.exports = { whenNoDirectory alreadyExists - validPermission + hasPermission isStoredInDotAtom makeSureDirectoryExists } diff --git a/spec/thread-spec.coffee b/spec/thread-spec.coffee deleted file mode 100644 index 9062e4d..0000000 --- a/spec/thread-spec.coffee +++ /dev/null @@ -1,124 +0,0 @@ -{ - threadF - threadL - injectAtLast - injectAtFirst - inject1B4L - overwrite - conditional - catchTrueWith -} = require '../lib/thread' - -sum=(a,b,c)-> - return a + b + c - -getC = (a,b,c) -> - c - -retFalse = (o) -> - false - -retTrue = (o) -> - true - -cb = (v, c) -> - if v == 0 - c() - return true - false - -class Temp - constructor: (@data=0) -> - - show: (something) -> - console.log something - - op: () -> - catchTrueWith @data, (t) => - t cb, => - @show "this should work" - -describe 'Thread', -> - - describe 'threadF', -> - it 'checking the value with simple sums and argument getters', -> - total = threadF 0, (t) => - t sum, 1, 2 - t sum, 4, 5 - t sum, 13,14 - expect(total).toEqual 39 - - total2 = threadF 1, (t) => - t getC, null, 5 - expect(total2).toEqual 5 - - describe 'threadL', -> - it 'should inject value at last place in arg', -> - output = threadL 5, (t) => - t getC, 1, 2 - t sum, 1, 2 - - expect(output).toEqual 8 - - describe 'when using withing an object deifinition', -> - beforeEach -> - @obj = new Temp - - it 'show allow using the @ operator ', -> - spyOn(@obj, 'show') - expect(@obj.op()).toEqual true - expect(@obj.show).toHaveBeenCalledWith 'this should work' - expect(@obj.show.mostRecentCall.args[0]).toEqual 'this should work' - - -describe 'injectors', -> - beforeEach -> - @OBJ = class Obj - constructor: () -> @value = 1 - - describe 'injectAtFirst', -> - it 'should insert 1 at the first place of [2 3 4]', -> - finalArgList = injectAtFirst.call(new @OBJ,[2,3,4]) - expect(finalArgList).toEqual [1,2,3,4] - - describe 'injectAtLast', -> - it 'should insert 1 at the last place of [2 3 4]', -> - finalArgList = injectAtLast.call(new @OBJ,[2,3,4]) - expect(finalArgList).toEqual [2,3,4,1] - - describe 'inject1B4L', -> - it 'should insert 1 at the second to last place of [2 3 4]', -> - finalArgList = inject1B4L.call(new @OBJ,[2,3,4]) - expect(finalArgList).toEqual [2,3,1,4] - -describe 'assigners', -> - beforeEach -> - @OBJ = class Obj - constructor: () -> @value = 1 - - describe 'overwrite', -> - it 'should become `cool` when calling overwrite', -> - obj = new @OBJ - expect(obj.value).toEqual 1 - overwrite.call(obj, 'cool') - expect(obj.value).toEqual 'cool' - - describe 'conditional', -> - describe 'when conditional(true)', -> - it 'should overwrite the value when the value is equal to true', -> - obj = new @OBJ - catchTrue = conditional(true) - expect(obj.value).toEqual 1 - catchTrue.call(obj, true) - catchTrue.call(obj, false) - expect(obj.value).toEqual 1 - expect(obj.cond).toEqual true - - it 'should not overwirte the value with true if it down not see it', -> - obj = new @OBJ - catchTrue = conditional(true) - expect(obj.value).toEqual 1 - catchTrue.call(obj, false) - catchTrue.call(obj, false) - expect(obj.value).toEqual 1 - expect(obj.cond).toEqual false