boom 0.2.4 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,81 +0,0 @@
1
- # coding: utf-8
2
-
3
- # Storage is the middleman between changes the client makes in-memory and how
4
- # it's actually persisted to disk (and vice-versa). There are also a few
5
- # convenience methods to run searches and operations on the in-memory hash.
6
- #
7
- module Boom
8
- module Storage
9
- class Base
10
-
11
- # Public: initializes a Storage instance by loading in your persisted data from adapter.
12
- #
13
- # Returns the Storage instance.
14
- def initialize
15
- @lists = []
16
- bootstrap
17
- populate
18
- end
19
-
20
- # run bootstrap tasks for the storage
21
- def bootstrap ; end
22
-
23
- # populate the in-memory store with all the lists and items
24
- def populate ; end
25
-
26
- # save the data
27
- def save ; end
28
-
29
- # Public: the in-memory collection of all Lists attached to this Storage
30
- # instance.
31
- #
32
- # lists - an Array of individual List items
33
- #
34
- # Returns nothing.
35
- attr_writer :lists
36
-
37
- # Public: the list of Lists in your JSON data, sorted by number of items
38
- # descending.
39
- #
40
- # Returns an Array of List objects.
41
- def lists
42
- @lists.sort_by { |list| -list.items.size }
43
- end
44
-
45
- # Public: tests whether a named List exists.
46
- #
47
- # name - the String name of a List
48
- #
49
- # Returns true if found, false if not.
50
- def list_exists?(name)
51
- @lists.detect { |list| list.name == name }
52
- end
53
-
54
- # Public: all Items in storage.
55
- #
56
- # Returns an Array of all Items.
57
- def items
58
- @lists.collect(&:items).flatten
59
- end
60
-
61
- # Public: tests whether a named Item exists.
62
- #
63
- # name - the String name of an Item
64
- #
65
- # Returns true if found, false if not.
66
- def item_exists?(name)
67
- items.detect { |item| item.name == name }
68
- end
69
-
70
- # Public: creates a Hash of the representation of the in-memory data
71
- # structure. This percolates down to Items by calling to_hash on the List,
72
- # which in tern calls to_hash on individual Items.
73
- #
74
- # Returns a Hash of the entire data set.
75
- def to_hash
76
- { :lists => lists.collect(&:to_hash) }
77
- end
78
-
79
- end
80
- end
81
- end
@@ -1,114 +0,0 @@
1
- # coding: utf-8
2
- #
3
- # Gist backend for Boom.
4
- #
5
- # Your .boom.conf file should look like this:
6
- #
7
- # {
8
- # "backend": "gist",
9
- # "gist": {
10
- # "username": "your_github_username",
11
- # "password": "your_github_password"
12
- # }
13
- # }
14
- #
15
- # There are two optional keys which can be under "gist":
16
- #
17
- # gist_id - The ID of an existing Gist to use. If not
18
- # present, a Gist will be created the first time
19
- # Boom is run and will be persisted to the config.
20
- # public - Makes the Gist public. An absent value or
21
- # any value other than boolean true will make
22
- # the Gist private.
23
- #
24
-
25
- module Boom
26
- module Storage
27
- class Gist < Base
28
-
29
- def bootstrap
30
- begin
31
- require "httparty"
32
-
33
- self.class.send(:include, HTTParty)
34
- self.class.base_uri "https://api.github.com"
35
- rescue LoadError
36
- puts "The Gist backend requires HTTParty: gem install httparty"
37
- exit
38
- end
39
-
40
- unless Boom.config.attributes["gist"]
41
- puts 'A "gist" data structure must be defined in ~/.boom.conf'
42
- exit
43
- end
44
-
45
- set_up_auth
46
- find_or_create_gist
47
- end
48
-
49
- def populate
50
- @storage['lists'].each do |lists|
51
- lists.each do |list_name, items|
52
- @lists << list = List.new(list_name)
53
-
54
- items.each do |item|
55
- item.each do |name,value|
56
- list.add_item(Item.new(name,value))
57
- end
58
- end
59
- end
60
- end
61
- end
62
-
63
- def save
64
- self.class.post("/gists/#{@gist_id}", request_params)
65
- end
66
-
67
- private
68
-
69
- def set_up_auth
70
- username, password = Boom.config.attributes["gist"]["username"], Boom.config.attributes["gist"]["password"]
71
-
72
- if username and password
73
- self.class.basic_auth(username, password)
74
- else
75
- puts "GitHub username and password must be defined in ~/.boom.conf"
76
- exit
77
- end
78
- end
79
-
80
- def find_or_create_gist
81
- @gist_id = Boom.config.attributes["gist"]["gist_id"]
82
- @public = Boom.config.attributes["gist"]["public"] == true
83
-
84
- if @gist_id.nil? or @gist_id.empty?
85
- response = self.class.post("/gists", request_params)
86
- else
87
- response = self.class.get("/gists/#{@gist_id}", request_params)
88
- end
89
-
90
- @storage = MultiJson.decode(response["files"]["boom.json"]["content"]) if response["files"] and response["files"]["boom.json"]
91
-
92
- unless @storage
93
- puts "Boom data could not be obtained"
94
- exit
95
- end
96
-
97
- unless @gist_id
98
- Boom.config.attributes["gist"]["gist_id"] = @gist_id = response["id"]
99
- Boom.config.save
100
- end
101
- end
102
-
103
- def request_params
104
- {
105
- :body => MultiJson.encode({
106
- :description => "boom!",
107
- :public => @public,
108
- :files => { "boom.json" => { :content => MultiJson.encode(to_hash) } }
109
- })
110
- }
111
- end
112
- end
113
- end
114
- end
@@ -1,69 +0,0 @@
1
- # coding: utf-8
2
- #
3
- # Json is the default storage option for boom. It writes a Json file to
4
- # ~/.boom. Pretty neat, huh?
5
- #
6
- module Boom
7
- module Storage
8
- class Json < Base
9
-
10
- JSON_FILE = "#{ENV['HOME']}/.boom"
11
-
12
- # Public: the path to the Json file used by boom.
13
- #
14
- # Returns the String path of boom's Json representation.
15
- def json_file
16
- JSON_FILE
17
- end
18
-
19
- # Takes care of bootstrapping the Json file, both in terms of creating the
20
- # file and in terms of creating a skeleton Json schema.
21
- #
22
- # Return true if successfully saved.
23
- def bootstrap
24
- return if File.exist?(json_file)
25
- FileUtils.touch json_file
26
- File.open(json_file, 'w') {|f| f.write(to_json) }
27
- save
28
- end
29
-
30
- # Take a Json representation of data and explode it out into the consituent
31
- # Lists and Items for the given Storage instance.
32
- #
33
- # Returns nothing.
34
- def populate
35
- storage = MultiJson.decode(File.new(json_file, 'r').read)
36
-
37
- storage['lists'].each do |lists|
38
- lists.each do |list_name, items|
39
- @lists << list = List.new(list_name)
40
-
41
- items.each do |item|
42
- item.each do |name,value|
43
- list.add_item(Item.new(name,value))
44
- end
45
- end
46
- end
47
- end
48
- end
49
-
50
- # Public: persists your in-memory objects to disk in Json format.
51
- #
52
- # lists_Json - list in Json format
53
- #
54
- # Returns true if successful, false if unsuccessful.
55
- def save
56
- File.open(json_file, 'w') {|f| f.write(to_json) }
57
- end
58
-
59
- # Public: the Json representation of the current List and Item assortment
60
- # attached to the Storage instance.
61
- #
62
- # Returns a String Json representation of its Lists and their Items.
63
- def to_json
64
- MultiJson.encode(to_hash)
65
- end
66
-
67
- end
68
- end
69
- end
@@ -1,135 +0,0 @@
1
- # coding: utf-8
2
-
3
- # Keychain provides methods for using Mac OS X's Keychain as a storage option.
4
- # It saves lists as Keychain files in ~/Library/Keychains with the filename
5
- # format being: "Boom.list.mylist.keychain"
6
- #
7
- module Boom
8
- module Storage
9
- class Keychain < Base
10
-
11
- KEYCHAIN_FORMAT = %r{Boom\.list\.(.+)\.keychain}
12
-
13
- # Opens Keychain app when json_file is called during `boom edit`
14
- #
15
- # Returns nothing
16
- def open_keychain_app
17
- `open /Applications/Utilities/'Keychain Access.app' &`
18
- end
19
-
20
- alias_method :json_file, :open_keychain_app
21
-
22
- # Boostraps Keychain by checking if you're using a Mac which is a prereq
23
- #
24
- # Returns
25
- def bootstrap
26
- raise RuntimeError unless is_mac?
27
- rescue
28
- puts('No Keychain utility to access, maybe try another storage option?')
29
- exit
30
- end
31
-
32
- # Asks if you're using Mac OS X
33
- #
34
- # Returns true on a Mac
35
- def is_mac?
36
- return Boom::Platform.darwin?
37
- end
38
-
39
- # Populate the in-memory store with all the lists and items from Keychain
40
- #
41
- # Returns Array of keychain names, i.e. ["Boom.list.mylist.keychain"]
42
- def populate
43
- stored_keychain_lists.each do |keychain|
44
- @lists << list = List.new(keychain.scan(KEYCHAIN_FORMAT).flatten.first)
45
- extract_keychain_items(keychain).each do |name|
46
- list.add_item(Item.new(name, extract_keychain_value(name, keychain)))
47
- end
48
- end
49
- end
50
-
51
- # Saves the data from memory to the correct Keychain
52
- #
53
- # Returns nothing
54
- def save
55
- @lists.each do |list|
56
- keychain_name = list_to_filename(list.name)
57
- create_keychain_list(keychain_name) unless stored_keychain_lists.include?(keychain_name)
58
- unless list.items.empty?
59
- list.items.each do |item|
60
- store_item(item, keychain_name)
61
- end
62
- end
63
- delete_unwanted_items(list)
64
- end
65
- delete_unwanted_lists
66
- rescue RuntimeError
67
- puts(e "Couldn't save to your keychain, check Console.app or above for relevant messages")
68
- end
69
-
70
-
71
- private
72
-
73
- # Returns an Array of keychains stored in ~/Library/Keychains:
74
- # => ["Boom.list.mylist.keychain"]
75
- def stored_keychain_lists
76
- @stored_keychain_lists ||= `security -q list-keychains |grep Boom.list` \
77
- .split(/[\/\n\"]/).select {|kc| kc =~ KEYCHAIN_FORMAT}
78
- end
79
-
80
- # Create the keychain list "Boom.list.mylist.keychain" in ~/Library/Keychains
81
- def create_keychain_list(keychain_name)
82
- `security -q create-keychain #{keychain_name}`
83
- end
84
-
85
- # Saves the individual item's value to the right list/keychain
86
- def store_item(item, keychain_name)
87
- `security 2>/dev/null -q add-generic-password -a '#{item.name}' -s '#{item.name}' -w '#{item.value}' #{keychain_name}`
88
- end
89
-
90
- # Retrieves the value of a particular item in a list
91
- def extract_keychain_value(item_name, keychain)
92
- `security 2>&1 >/dev/null find-generic-password -ga '#{item_name}' #{keychain}`.chomp.split('"').last
93
- end
94
-
95
- # Gets all items in a particular list
96
- def extract_keychain_items(keychain_name)
97
- @stored_items ||= {}
98
- @stored_items[keychain_name] ||= `security dump-keychain -a #{keychain_name} |grep acct` \
99
- .split(/\s|\\n|\\"|acct|<blob>=|\"/).reject {|f| f.empty?}
100
- end
101
-
102
- # Converts list name to the corresponding keychain filename format based
103
- # on the KEYCHAIN_FORMAT
104
- def list_to_filename(list_name)
105
- KEYCHAIN_FORMAT.source.gsub(/\(\.\+\)/, list_name).gsub('\\','')
106
- end
107
-
108
- # Delete's a keychain file
109
- def delete_list(keychain_filename)
110
- `security delete-keychain #{keychain_filename}`
111
- end
112
-
113
- # Delete's all keychain files you don't want anymore
114
- def delete_unwanted_lists
115
- (stored_keychain_lists - @lists.map {|list| list_to_filename(list.name)}).each do |filename|
116
- delete_list(filename)
117
- end
118
- end
119
-
120
- # Removes unwanted items in a list
121
- # security util doesn't have a delete password option so we'll have to
122
- # drop it and recreate it with what is in memory
123
- def delete_unwanted_items(list)
124
- filename = list_to_filename(list.name)
125
- if (list.items.size < extract_keychain_items(filename).size)
126
- delete_list(filename)
127
- create_keychain_list(filename)
128
- list.items.each do |item|
129
- store_item(item, filename)
130
- end unless list.items.empty?
131
- end
132
- end
133
- end
134
- end
135
- end
@@ -1,84 +0,0 @@
1
- # coding: utf-8
2
-
3
- # Storage adapter that saves data from boom to MongoDB instead of JSON file.
4
- begin
5
- require 'mongo'
6
- rescue LoadError
7
- end
8
-
9
- module Boom
10
- module Storage
11
- class Mongodb < Base
12
-
13
- # Public: Initialize MongoDB connection and check dep.
14
- #
15
- # Returns Mongo connection
16
- def mongo
17
- @mongo ||= ::Mongo::Connection.new(
18
- Boom.config.attributes["mongodb"]["host"],
19
- Boom.config.attributes["mongodb"]["port"]
20
- ).db(Boom.config.attributes["mongodb"]["database"])
21
-
22
- @mongo.authenticate(
23
- Boom.config.attributes['mongodb']['username'],
24
- Boom.config.attributes['mongodb']['password']
25
- )
26
-
27
- # Return connection
28
- @mongo
29
- rescue NameError => e
30
- puts "You don't have the Mongo gem installed yet:\n gem install mongo"
31
- exit
32
- end
33
-
34
- # Public: The MongoDB collection
35
- #
36
- # Returns the MongoDB collection
37
- def collection
38
- @collection ||= mongo.collection(Boom.config.attributes["mongodb"]["collection"])
39
- end
40
-
41
- # Public: Bootstrap
42
- #
43
- # Returns
44
- def bootstrap
45
- collection.insert("boom" => '{"lists": [{}]}') if collection.find_one.nil?
46
- end
47
-
48
- # Public: Populates the memory list from MongoDB
49
- #
50
- # Returns nothing
51
- def populate
52
- storage = MultiJson.decode(collection.find_one['boom']) || []
53
-
54
- storage['lists'].each do |lists|
55
- lists.each do |list_name, items|
56
- @lists << list = List.new(list_name)
57
-
58
- items.each do |item|
59
- item.each do |name,value|
60
- list.add_item(Item.new(name,value))
61
- end
62
- end
63
- end
64
- end
65
- end
66
-
67
- # Public: Save to MongoDB
68
- #
69
- # Returns Mongo ID
70
- def save
71
- doc = collection.find_one()
72
- collection.update({"_id" => doc["_id"]}, {'boom' => to_json})
73
- end
74
-
75
- # Public: Convert to JSON
76
- #
77
- # Returns
78
- def to_json
79
- MultiJson.encode(to_hash)
80
- end
81
-
82
- end
83
- end
84
- end
@@ -1,72 +0,0 @@
1
- # coding: utf-8
2
- #
3
- # Sup, Redis.
4
- #
5
- begin
6
- require 'digest'
7
- require 'redis'
8
- require 'uri'
9
- rescue LoadError
10
- end
11
-
12
- module Boom
13
- module Storage
14
- class Redis < Base
15
-
16
- def redis
17
- uri = URI.parse(Boom.config.attributes['uri'] || '')
18
-
19
- @redis ||= ::Redis.new :host => (uri.host || Boom.config.attributes["redis"]["host"]),
20
- :port => (uri.port || Boom.config.attributes["redis"]["port"]),
21
- :user => (uri.user || Boom.config.attributes["redis"]["user"]),
22
- :password => (uri.password || Boom.config.attributes["redis"]["password"])
23
- rescue NameError => e
24
- puts "You don't have Redis installed yet:\n gem install redis"
25
- exit
26
- end
27
-
28
- def bootstrap
29
- end
30
-
31
- def populate
32
- lists = redis.smembers("boom:lists") || []
33
-
34
- lists.each do |sha|
35
- list_name = redis.get("boom:lists:#{sha}:name")
36
- @lists << list = List.new(list_name)
37
-
38
- shas = redis.lrange("boom:lists:#{sha}:items",0,-1) || []
39
-
40
- shas.each do |item_sha|
41
- name = redis.get "boom:items:#{item_sha}:name"
42
- value = redis.get "boom:items:#{item_sha}:value"
43
- list.add_item(Item.new(name, value))
44
- end
45
- end
46
- end
47
-
48
- def clear
49
- redis.del "boom:lists"
50
- redis.del "boom:items"
51
- end
52
-
53
- def save
54
- clear
55
-
56
- lists.each do |list|
57
- list_sha = Digest::SHA1.hexdigest(list.name)
58
- redis.set "boom:lists:#{list_sha}:name", list.name
59
- redis.sadd "boom:lists", list_sha
60
-
61
- list.items.each do |item|
62
- item_sha = Digest::SHA1.hexdigest(item.name)
63
- redis.rpush "boom:lists:#{list_sha}:items", item_sha
64
- redis.set "boom:items:#{item_sha}:name", item.name
65
- redis.set "boom:items:#{item_sha}:value", item.value
66
- end
67
- end
68
- end
69
-
70
- end
71
- end
72
- end
@@ -1,3 +0,0 @@
1
- {
2
- backend: 'Json'
3
- }
@@ -1,3 +0,0 @@
1
- {
2
- "backend": "Json"
3
- }
@@ -1 +0,0 @@
1
- {"lists":[{"urls":[{"github":"https://github.com"},{"blog":"http://zachholman.com"}]}]}
data/test/helper.rb DELETED
@@ -1,24 +0,0 @@
1
- # coding: utf-8
2
-
3
- require 'test/unit'
4
-
5
- begin
6
- require 'rubygems'
7
- require 'redgreen'
8
- rescue LoadError
9
- end
10
-
11
- require 'mocha'
12
-
13
- $LOAD_PATH.unshift(File.dirname(__FILE__))
14
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
15
-
16
- require 'boom'
17
-
18
- def boom_json(name)
19
- root = File.expand_path(File.dirname(__FILE__))
20
- Boom::Storage::Json.any_instance.stubs(:save).returns(true)
21
- Boom::Storage::Json.any_instance.stubs(:json_file).
22
- returns("#{root}/examples/#{name}.json")
23
- Boom.stubs(:storage).returns(Boom::Storage::Json.new)
24
- end
data/test/test_color.rb DELETED
@@ -1,30 +0,0 @@
1
- require 'helper'
2
-
3
- class TestColor < Test::Unit::TestCase
4
-
5
- def test_colorize
6
- assert_equal "\e[35mBoom!\e[0m",
7
- Boom::Color.colorize("Boom!", :magenta)
8
- end
9
-
10
- def test_magenta
11
- assert_equal "\e[35mMagenta!\e[0m",
12
- Boom::Color.magenta("Magenta!")
13
- end
14
-
15
- def test_red
16
- assert_equal "\e[31mRed!\e[0m",
17
- Boom::Color.red("Red!")
18
- end
19
-
20
- def test_yellow
21
- assert_equal "\e[33mYellow!\e[0m",
22
- Boom::Color.yellow("Yellow!")
23
- end
24
-
25
- def test_cyan
26
- assert_equal "\e[36mCyan!\e[0m",
27
- Boom::Color.cyan("Cyan!")
28
- end
29
-
30
- end