Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Breaking It Down!

Ken Collins
October 11, 2013

Breaking It Down!

Dive into my personal thought process on how to develop large feature sets. Along the way, we will explore componentizing a user interface deliverable in JavaScript (really CoffeeScript) while testing it along the way via Mocha.js. Lets iterate to success!

Ken Collins

October 11, 2013
Tweet

More Decks by Ken Collins

Other Decks in Technology

Transcript

  1. Great Developer Skills 2 * Really understanding the goal. *

    Start at the end!!! * Creative and technical possibilities. * Abstraction can yield yak shaving moments.
  2. def show sound = Sound.find(params[:id]) @xml_path = File.dirname(sound.file.path) s3 =

    AWS::S3.new(:access_key_id => 'XXX', :secret_access_key => 'XXX') @url = s3.buckets['dev'].objects[sound.file.path[1..-1]].url_for(:read, :expires => 10*60) if sound.id_job != 0 && sound.transcript_progress != 100 @response = Savon.client("http://srap.php?wsdl").request(:avance) do soap.body = {:Jeton => "abcdef", :ID_job => sound.id_job,} end @response = @response.to_hash @progress = @response[:avance][:avancement].to_s.split("#")[1]keep "123" if @progress == "Termine" sound.transcript_progress = 100 elsif @progress == "ERROR" flash.now[:alert] = "Oups, il semblerait que le fichier soit illisible, ou qu'il n'y ait rien a ecouter !" elsif @progress != "Queued" sound.transcript_progress = @response[:avance_response][:avancement].to_s.split("#")[2].split("%") [0].to_i end sound.save end if sound.transcript_progress == 100 # If transcription finished # Get XML File URL on the FTP @xml_path = Savon.client("http://srap.php?wsdl").request(:donneResultat) do soap.body = {:Jeton => "XXX", :FichierSon => sound.id_job} end # Parse XML Path URL on Kimsufi @xml_path = @xml_path.to_hash[:donne_resultat_transposition_response][:chemin_fichier].to_s.split("#") [2].to_s.split("/")[5] # Create local directory (/tmp/sounds) for XML Temp Save if ! File.directory?(Rails.root.to_s + '/tmp/sounds') Dir.mkdir(Rails.root.to_s + '/tmp/sounds') end # Get XML from FTP ftp=Net::FTP.new ftp.connect("ftp.com", 21) ftp.login("XXX", "XXX") if ftp.closed? flash.now[:alert] = "Oups, il semblerait qu'il y ait eu un problème ! Merci d'actualiser la page" else ftp.passive = true ftp.chdir('results') ftp.getbinaryfile(@xml_path, Rails.root.to_s + '/tmp/sounds/' + @xml_path) ftp.close end Self Reflection 3 Poor Soul On Stack Overflow - http://bit.ly/NoLo5A What went wrong? - Using SOAP - No. -
  3. Lets TDD This... 8 Using Mocha.js, Chai.js assertions all under

    Konacha. Will give a link to holy_grail_harness if this interests you.
  4. class ListReflection constructor: (@_klass, @_name, options = {}) -> scopeName:

    -> scopeClass: -> scopeAttribute: -> listName: -> listNamePlural: -> listNameTitleized: -> listNameLower: -> listModelClass: -> listViewClass: -> listView: (params={}) -> itemViewClass: -> itemView: (params={}) -> itemSelector: -> subListPresent: -> subListNameTitleized: -> subListNameLower: -> subListNamePlural: -> subListName: -> subListModelClass: -> subListControllerClass: -> subListSelector: -> subListModels: (item) -> What I Currently Had 9 ListReflectionExtend = configureList: (name, opts = {}) -> @listReflection = new ListReflection this, name, opts ListReflectionInclude = listReflection: -> @constructor.listReflection @HomeMarks.ListReflection = extended: -> @extend ListReflectionExtend @include ListReflectionInclude DSL for declaring lists. List view class and rendering. Item view class and rendering. Sub list names for DOM and Model reflection.
  5. # Controllers class @HomeMarks.App.Columns extends HomeMarks.Controllers.List @configureList 'Columns', subListName: 'Boxes'

    class @HomeMarks.App.Boxes extends HomeMarks.Controllers.List @configureList 'Boxes', subListName: 'Bookmarks' class @HomeMarks.App.Bookmarks extends HomeMarks.Controllers.List @configureList 'Bookmarks' # Model class @HomeMarks.App.Column extends HomeMarks.Models.List @configureList 'Columns', listScope: 'User', subListName: 'Boxes' class @HomeMarks.App.Box extends HomeMarks.Models.List @configureList 'Boxes', listScope: 'Column', subListName: 'Bookmarks' class @HomeMarks.App.Bookmark extends HomeMarks.Models.List @configureList 'Bookmarks', listScope: 'Box' What I Currently Had 10
  6. Lets TDD This... 12 * Just like super controller code,

    tests (EVEN SETUP) should be really small! * If your test setup is long winded, you need to go build something.
  7. 13 TDD With Mocha.js & Konacha +S These tools/reflection is

    what allowed this page to be rendered.
  8. 14 TDD With Mocha.js & Konacha $ rake konacha:serve $

    open http://localhost:3500/homemarks/models/bookmark_spec
  9. Lets TDD This... 16 * Decided I wanted to go

    in CRUD order. * Let’s create first.
  10. box = boxes 'JavaScript' box.bookmarks().create name: 'Mocha.js' url: 'http://visionmedia.github.io/mocha/' What

    I Wanted 17 * Simple command to create. * Models would do what I wanted! * Views would react!
  11. ActsAsList 18 • Low Level Implementation (Private) –inList() –removeFromList() –incrementPositionsOnAllItems()

    –decrementPositionsOnLowerItems() –incrementPositionsOnLowerItem(newPosition) Used existing ruby implementation.
  12. 21 #= require spec_helper describe 'HomeMarks.Models.List', -> beforeEach -> @column1

    = columns(0) @column2 = columns(1) @column3 = columns(2) @bm1 = bookmarks('Ruby On Rails') @bm2 = bookmarks('Rubyflow') @bm3 = bookmarks('Rubygems.org') @bm4 = bookmarks('Ruby Language') it.only 'inList', -> expect(@column1.inList()).to.be.true @column1.position = null expect(@column1.inList()).to.be.false @column1.position = undefined expect(@column1.inList()).to.be.false it 'removeFromList', -> it 'incrementPositionsOnAllItems', -> it 'incrementPositionsOnLowerItems', -> it 'decrementPositionsOnLowerItems', -> AAL Implementation
  13. 22 inList: -> @position? removeFromList: -> @position = null Spine.Ajax.disable

    => @save() incrementPositionsOnAllItems: -> return unless @inList() items = @listItems() Spine.Ajax.disable -> for item in items item.position = item.position + 1 item.save() decrementPositionsOnLowerItems: -> return unless @inList() position = @position items = (item for item in @listItems() when item.position > position) Spine.Ajax.disable -> for item in items item.position = item.position - 1 item.save() incrementPositionsOnLowerItems: (newPosition) -> items = (item for item in @listItems() when item.position >= newPosition) Spine.Ajax.disable -> for item in items item.position = item.position + 1 item.save() AAL Implementation
  14. 23 class @HomeMarks.Models.List extends HomeMarks.Models.Base @extend HomeMarks.ListBehavior constructor: (atts) ->

    super @bind 'beforeCreate', @addToListTop @bind 'beforeDestroy', @removeFromList AAL Lifecycle Hooks
  15. 24 addToListTop: -> @position = 1 @incrementPositionsOnAllItems() @one 'save', @addToListTopEl

    addToListTopEl: -> item = @listReflection().itemView model: this items = @scopeParentContainer() items.prepend item AAL Lifecycle Hooks
  16. 26 # spec_helper/fixtures.js.coffee @hmCreateBookmark = (done) -> box = boxes('JavaScript')

    d = -> done() f = -> console.log "The hmCreateBookmark() request failed." ; done() $.mockjax url: "#{box.hmURL()}/bookmarks/", responseText: JSON.stringify(id: 323) box.bookmarks().create {name: 'Mocha.js', url: 'http://visionmedia.github.io/mocha/'}, {done: d, fail: f} # bookmark_spec.js.coffee it 'create', (done) -> box = boxes('JavaScript') hmCreateBookmark => bm = box.bookmarks().allSorted()[0] expect(bm.isNew()).to.be.false expect(bm.id).to.equal 323 expect(bm.position).to.equal 1 expect(@bm1.position).to.equal 2 expect(@bm2.position).to.equal 3 # Builds the element. bmEl = box.el.find '.bookmark:first' link = bmEl.find '.bookmark-link' expect(link).to.have.text 'Mocha.js' expect(link).to.have.attr 'href', 'http://visionmedia.github.io/mocha/' expect(bmEl.hmModel()).to.deep.equal bm done() AAL Lifecycle Hooks