├── arrays.go ├── bulkload ├── .rvmrc ├── Gemfile ├── Gemfile.lock ├── Rakefile ├── db │ ├── .gitignore │ ├── config.yml.sample │ ├── migrate │ │ ├── 20130302134949_create_models.rb │ │ └── 20130302141645_add_tags.rb │ └── schema.rb ├── generate_csv.go └── lib │ └── item.rb ├── csv-parsing.go ├── data └── sample.csv ├── download-files.go ├── hello-world.go └── web ├── app.go └── index.html /arrays.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var numbers [10]int 7 | 8 | for i := 0; i < len(numbers); i++ { 9 | numbers[i] = i * 3 10 | } 11 | 12 | fmt.Println("Here are some numbers:", numbers) 13 | 14 | for i := 0; i < len(numbers); i++ { 15 | var parity string 16 | if numbers[i]%2 == 0 { 17 | parity = "even" 18 | } else { 19 | parity = "odd" 20 | } 21 | fmt.Printf("Number %d is %s\n", numbers[i], parity) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /bulkload/.rvmrc: -------------------------------------------------------------------------------- 1 | rvm use ruby-2.0.0-p0@bulkload --create -------------------------------------------------------------------------------- /bulkload/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://www.rubygems.org' 2 | 3 | gem 'mysql2' 4 | gem 'activerecord' 5 | gem 'standalone_migrations' 6 | 7 | gem 'rocket_tag', github: 'bradphelan/rocket_tag', ref: 'a47b3340' 8 | 9 | gem 'awesome_print' -------------------------------------------------------------------------------- /bulkload/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GIT 2 | remote: git://github.com/bradphelan/rocket_tag.git 3 | revision: a47b3340621dc36afa5559458eec9512384a87ba 4 | ref: a47b3340 5 | specs: 6 | rocket_tag (0.5.6) 7 | activerecord (>= 3.2.0) 8 | squeel (~> 1.0.0) 9 | 10 | GEM 11 | remote: https://www.rubygems.org/ 12 | specs: 13 | actionpack (3.2.12) 14 | activemodel (= 3.2.12) 15 | activesupport (= 3.2.12) 16 | builder (~> 3.0.0) 17 | erubis (~> 2.7.0) 18 | journey (~> 1.0.4) 19 | rack (~> 1.4.5) 20 | rack-cache (~> 1.2) 21 | rack-test (~> 0.6.1) 22 | sprockets (~> 2.2.1) 23 | activemodel (3.2.12) 24 | activesupport (= 3.2.12) 25 | builder (~> 3.0.0) 26 | activerecord (3.2.12) 27 | activemodel (= 3.2.12) 28 | activesupport (= 3.2.12) 29 | arel (~> 3.0.2) 30 | tzinfo (~> 0.3.29) 31 | activesupport (3.2.12) 32 | i18n (~> 0.6) 33 | multi_json (~> 1.0) 34 | arel (3.0.2) 35 | awesome_print (1.1.0) 36 | builder (3.0.4) 37 | erubis (2.7.0) 38 | hike (1.2.1) 39 | i18n (0.6.4) 40 | journey (1.0.4) 41 | json (1.7.7) 42 | multi_json (1.6.1) 43 | mysql2 (0.3.11) 44 | polyamorous (0.5.0) 45 | activerecord (~> 3.0) 46 | rack (1.4.5) 47 | rack-cache (1.2) 48 | rack (>= 0.4) 49 | rack-ssl (1.3.3) 50 | rack 51 | rack-test (0.6.2) 52 | rack (>= 1.0) 53 | railties (3.2.12) 54 | actionpack (= 3.2.12) 55 | activesupport (= 3.2.12) 56 | rack-ssl (~> 1.3.2) 57 | rake (>= 0.8.7) 58 | rdoc (~> 3.4) 59 | thor (>= 0.14.6, < 2.0) 60 | rake (10.0.3) 61 | rdoc (3.12.2) 62 | json (~> 1.4) 63 | sprockets (2.2.2) 64 | hike (~> 1.2) 65 | multi_json (~> 1.0) 66 | rack (~> 1.0) 67 | tilt (~> 1.1, != 1.3.0) 68 | squeel (1.0.17) 69 | activerecord (~> 3.0) 70 | activesupport (~> 3.0) 71 | polyamorous (~> 0.5.0) 72 | standalone_migrations (2.0.5) 73 | activerecord (~> 3.2.11) 74 | railties (~> 3.2.11) 75 | rake 76 | thor (0.17.0) 77 | tilt (1.3.4) 78 | tzinfo (0.3.35) 79 | 80 | PLATFORMS 81 | ruby 82 | 83 | DEPENDENCIES 84 | activerecord 85 | awesome_print 86 | mysql2 87 | rocket_tag! 88 | standalone_migrations 89 | -------------------------------------------------------------------------------- /bulkload/Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler' 2 | require 'active_record' 3 | require 'awesome_print' 4 | require 'yaml' 5 | 6 | require 'standalone_migrations' 7 | StandaloneMigrations::Tasks.load_tasks 8 | 9 | task :hello => 'standalone:connection' do 10 | require './lib/item' 11 | puts Item.count 12 | end 13 | 14 | require 'csv' 15 | task :generate_csv do 16 | CSV.open('ruby-data.csv', 'w') do |f| 17 | f << [:guid, :some_field, :some_other_field] 18 | 15000000.times do |counter| 19 | f << ["guid_#{counter}", "some_field_#{counter}", "some_other_field_#{counter}"] 20 | end 21 | end 22 | end -------------------------------------------------------------------------------- /bulkload/db/.gitignore: -------------------------------------------------------------------------------- 1 | *.yml -------------------------------------------------------------------------------- /bulkload/db/config.yml.sample: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: mysql2 3 | encoding: utf8 4 | reconnect: false 5 | database: bulkload_dev 6 | pool: 5 7 | username: 8 | password: 9 | -------------------------------------------------------------------------------- /bulkload/db/migrate/20130302134949_create_models.rb: -------------------------------------------------------------------------------- 1 | class CreateModels < ActiveRecord::Migration 2 | def change 3 | create_table(:items) do |t| 4 | t.string :guid 5 | t.string :some_field 6 | t.string :some_other_field 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /bulkload/db/migrate/20130302141645_add_tags.rb: -------------------------------------------------------------------------------- 1 | class AddTags < ActiveRecord::Migration 2 | def self.up 3 | create_table :tags do |t| 4 | t.string :name 5 | end 6 | 7 | create_table :taggings do |t| 8 | t.references :tag 9 | 10 | # You should make sure that the column created is 11 | # long enough to store the required class names. 12 | t.references :taggable, :polymorphic => true 13 | t.references :tagger, :polymorphic => true 14 | 15 | t.string :context 16 | 17 | t.datetime :created_at 18 | end 19 | 20 | add_index :taggings, :tag_id 21 | add_index :taggings, [:taggable_id, :taggable_type, :context] 22 | 23 | create_table :alias_tags, :id => false do |t| 24 | t.integer :tag_id 25 | t.integer :alias_id 26 | end 27 | 28 | add_index :alias_tags, :tag_id 29 | add_index :alias_tags, :alias_id 30 | end 31 | 32 | def self.down 33 | drop_table :taggings 34 | drop_table :tags 35 | drop_table :alias_tags 36 | end 37 | end -------------------------------------------------------------------------------- /bulkload/db/schema.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # This file is auto-generated from the current state of the database. Instead 3 | # of editing this file, please use the migrations feature of Active Record to 4 | # incrementally modify your database, and then regenerate this schema definition. 5 | # 6 | # Note that this schema.rb definition is the authoritative source for your 7 | # database schema. If you need to create the application database on another 8 | # system, you should be using db:schema:load, not running all the migrations 9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 10 | # you'll amass, the slower it'll run and the greater likelihood for issues). 11 | # 12 | # It's strongly recommended to check this file into your version control system. 13 | 14 | ActiveRecord::Schema.define(:version => 20130302141645) do 15 | 16 | create_table "alias_tags", :id => false, :force => true do |t| 17 | t.integer "tag_id" 18 | t.integer "alias_id" 19 | end 20 | 21 | add_index "alias_tags", ["alias_id"], :name => "index_alias_tags_on_alias_id" 22 | add_index "alias_tags", ["tag_id"], :name => "index_alias_tags_on_tag_id" 23 | 24 | create_table "items", :force => true do |t| 25 | t.string "guid" 26 | t.string "some_field" 27 | t.string "some_other_field" 28 | t.datetime "created_at", :null => false 29 | t.datetime "updated_at", :null => false 30 | end 31 | 32 | create_table "taggings", :force => true do |t| 33 | t.integer "tag_id" 34 | t.integer "taggable_id" 35 | t.string "taggable_type" 36 | t.integer "tagger_id" 37 | t.string "tagger_type" 38 | t.string "context" 39 | t.datetime "created_at" 40 | end 41 | 42 | add_index "taggings", ["tag_id"], :name => "index_taggings_on_tag_id" 43 | add_index "taggings", ["taggable_id", "taggable_type", "context"], :name => "index_taggings_on_taggable_id_and_taggable_type_and_context" 44 | 45 | create_table "tags", :force => true do |t| 46 | t.string "name" 47 | end 48 | 49 | end 50 | -------------------------------------------------------------------------------- /bulkload/generate_csv.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "encoding/csv" 4 | import "os" 5 | 6 | import "flag" 7 | import "strconv" 8 | 9 | func main() { 10 | numberOfRecords := flag.Int("count", 15000000, "number of records to be generated") 11 | flag.Parse() 12 | 13 | file, err := os.Create("go-data.csv") 14 | if err != nil { 15 | panic(err) 16 | } 17 | defer file.Close() 18 | 19 | writer := csv.NewWriter(file) 20 | defer writer.Flush() 21 | 22 | writer.Write([]string{"guid", "some_field", "some_other_field"}) 23 | for i := 0; i < *numberOfRecords; i++ { 24 | record := []string{ 25 | "guid_" + strconv.Itoa(i), 26 | "some_field_" + strconv.Itoa(i), 27 | "some_other_field_" + strconv.Itoa(i)} 28 | writer.Write(record) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /bulkload/lib/item.rb: -------------------------------------------------------------------------------- 1 | class Item < ActiveRecord::Base 2 | attr_taggable :tags 3 | 4 | validates_presence_of :guid, :some_field, :some_other_field 5 | end -------------------------------------------------------------------------------- /csv-parsing.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/csv" 5 | "fmt" 6 | "io" 7 | "os" 8 | ) 9 | 10 | // documentation for csv is at http://golang.org/pkg/encoding/csv/ 11 | // TODO: could not find 12 | func main() { 13 | file, err := os.Open("data/sample.csv") 14 | if err != nil { 15 | // err is printable 16 | // elements passed are separated by space automatically 17 | fmt.Println("Error:", err) 18 | return 19 | } 20 | // automatically call Close() at the end of current method 21 | defer file.Close() 22 | // 23 | reader := csv.NewReader(file) 24 | // options are available at: 25 | // http://golang.org/src/pkg/encoding/csv/reader.go?s=3213:3671#L94 26 | reader.Comma = ';' 27 | lineCount := 0 28 | for { 29 | // read just one record, but we could ReadAll() as well 30 | record, err := reader.Read() 31 | // end-of-file is fitted into err 32 | if err == io.EOF { 33 | break 34 | } else if err != nil { 35 | fmt.Println("Error:", err) 36 | return 37 | } 38 | // record is an array of string so is directly printable 39 | fmt.Println("Record", lineCount, "is", record, "and has", len(record), "fields") 40 | // and we can iterate on top of that 41 | for i := 0; i < len(record); i++ { 42 | fmt.Println(" ", record[i]) 43 | } 44 | fmt.Println() 45 | lineCount += 1 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /data/sample.csv: -------------------------------------------------------------------------------- 1 | first_name;last_name;ssn 2 | John;Barry;123456 3 | Kathy;Smith;687987 4 | Bob;McCornick;3979870 -------------------------------------------------------------------------------- /download-files.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net/http" 7 | "os" 8 | "strings" 9 | ) 10 | 11 | func downloadFromUrl(url string) { 12 | tokens := strings.Split(url, "/") 13 | fileName := tokens[len(tokens)-1] 14 | fmt.Println("Downloading", url, "to", fileName) 15 | 16 | // TODO: check file existence first with io.IsExist 17 | output, err := os.Create(fileName) 18 | if err != nil { 19 | fmt.Println("Error while creating", fileName, "-", err) 20 | return 21 | } 22 | defer output.Close() 23 | 24 | response, err := http.Get(url) 25 | if err != nil { 26 | fmt.Println("Error while downloading", url, "-", err) 27 | return 28 | } 29 | defer response.Body.Close() 30 | 31 | n, err := io.Copy(output, response.Body) 32 | if err != nil { 33 | fmt.Println("Error while downloading", url, "-", err) 34 | return 35 | } 36 | 37 | fmt.Println(n, "bytes downloaded.") 38 | } 39 | 40 | func main() { 41 | countries := []string{"GB", "FR", "ES", "DE", "CN", "CA", "ID", "US"} 42 | for i := 0; i < len(countries); i++ { 43 | url := "http://download.geonames.org/export/dump/" + countries[i] + ".zip" 44 | downloadFromUrl(url) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /hello-world.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | func main() { 9 | fmt.Println("Welcome! What's your name?") 10 | var name string 11 | fmt.Scanf("%s", &name) 12 | 13 | fmt.Println("Nice to have you onboard,", name) 14 | 15 | for i := 0; i < 10; i++ { 16 | fmt.Println(strings.Repeat("*", i)) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /web/app.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strconv" 9 | ) 10 | 11 | // http://golang.org/pkg/net/http/ 12 | 13 | // serve static page for one file manually (but we could do better here) 14 | func HtmlHandler(response http.ResponseWriter, req *http.Request) { 15 | var result, err = ioutil.ReadFile("index.html") 16 | if err != nil { 17 | // one can use http.Error to stop the processing and return an error 18 | http.Error(response, err.Error(), http.StatusInternalServerError) 19 | return 20 | } 21 | 22 | response.Header().Set("Content-Type", "text/html") 23 | response.Header().Set("Content-Length", strconv.Itoa(len(result))) 24 | fmt.Fprintf(response, "%s", result) 25 | } 26 | 27 | // use a struct to define my JSON output 28 | type Fruit struct { 29 | Name string `json:"name"` 30 | Price float64 `json:"unit_price"` 31 | AvailableQuantity int `json:"available_quantity"` 32 | } 33 | 34 | func JSONHandler(response http.ResponseWriter, req *http.Request) { 35 | var fruits = []Fruit{ 36 | Fruit{"Orange", 5.47, 150}, 37 | Fruit{"Apple", 1.20, 300}, 38 | Fruit{"Banana", 2.54, 37}, 39 | Fruit{"Kumquat", 3.57, 5}} 40 | // MarshalIndent let us pretty print json 41 | b, _ := json.MarshalIndent(fruits, "", " ") // TODO: handle error here 42 | response.Header().Set("Content-Type", "application/json") 43 | // TODO: set content length here 44 | response.Write(b) 45 | } 46 | 47 | func main() { 48 | port := "3000" 49 | http.HandleFunc("/", http.HandlerFunc(HtmlHandler)) 50 | http.HandleFunc("/data.json", http.HandlerFunc(JSONHandler)) 51 | fmt.Println("Listening on port", port) 52 | http.ListenAndServe((":" + port), nil) 53 | } 54 | -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 24 | 25 | 26 |
27 |
28 |
29 | 34 |
35 |
36 |
    37 |
  • 38 | {{ item.name }} / {{ formatMoney(item.unit_price) }} per unit / {{ item.available_quantity}} in stock 39 |
  • 40 |
41 |
42 |
43 |
44 | 55 | 56 | --------------------------------------------------------------------------------