kaboom 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,116 @@
1
+ # coding: utf-8
2
+
3
+ #
4
+ # Config manages all the config information for boom and its backends. It's a
5
+ # simple JSON Hash that gets persisted to `~/.boom` on-disk. You may access it
6
+ # as a Hash:
7
+ #
8
+ # config.attributes = { :backend => "JSON" }
9
+ # config.attributes[:backend]
10
+ # # => "json"
11
+ #
12
+ # config.attributes[:backend] = "Redis"
13
+ # config.attributes[:backend]
14
+ # # => "redis"
15
+ #
16
+ module Boom
17
+ class Config
18
+
19
+ # The main config file for boom
20
+ FILE = "#{ENV['HOME']}/.boom.conf"
21
+ REMOTE_FILE = FILE.gsub(/\.conf$/, ".remote.conf")
22
+
23
+ #if set to true then we will use a different config file for storage
24
+ #engine
25
+ attr_accessor :remote
26
+
27
+ # Public: The attributes Hash for configuration options. The attributes
28
+ # needed are dictated by each backend, but the `backend` option must be
29
+ # present.
30
+ attr_reader :attributes
31
+
32
+
33
+ # Public: an alias for accessing Boom.config.attributes[key]
34
+ # like Boom.config[key] instead
35
+ #
36
+ # Returns the value in the attributes hash
37
+ def [] key
38
+ attributes[key]
39
+ end
40
+
41
+ # Public: creates a new instance of Config.
42
+ #
43
+ # This will load the attributes from boom's config file, or bootstrap it
44
+ # if this is a new install. Bootstrapping defaults to the JSON backend.
45
+ #
46
+ # Returns nothing.
47
+ def initialize remote=false
48
+ @remote = remote
49
+ bootstrap unless File.exist?(file)
50
+ load_attributes
51
+ end
52
+
53
+ # Public: accessor for the configuration file.
54
+ #
55
+ # Returns the String file path.
56
+ def file
57
+ remote ? REMOTE_FILE : FILE
58
+ end
59
+
60
+ # Public: saves an empty, barebones hash to @attributes for the purpose of
61
+ # new user setup.
62
+ #
63
+ # Returns whether the attributes were saved.
64
+ def bootstrap
65
+ @attributes = {
66
+ :backend => 'json'
67
+ }
68
+ save
69
+ end
70
+
71
+ # Public: assigns a hash to the configuration attributes object. The
72
+ # contents of the attributes hash depends on what the backend needs. A
73
+ # `backend` key MUST be present, however.
74
+ #
75
+ # attrs - the Hash representation of attributes to persist to disk.
76
+ #
77
+ # Examples
78
+ #
79
+ # config.attributes = {"backend" => "json"}
80
+ #
81
+ # Returns whether the attributes were saved.
82
+ def attributes=(attrs)
83
+ @attributes = attrs
84
+ save
85
+ end
86
+
87
+ # Public: loads and parses the JSON tree from disk into memory and stores
88
+ # it in the attributes Hash.
89
+ #
90
+ # Returns nothing.
91
+ def load_attributes
92
+ @attributes = MultiJson.decode(File.new(file, 'r').read)
93
+ end
94
+
95
+ # Public: writes the in-memory JSON Hash to disk.
96
+ #
97
+ # Returns nothing.
98
+ def save
99
+ json = MultiJson.encode(attributes)
100
+ File.open(file, 'w') {|f| f.write(json) }
101
+ end
102
+
103
+ def invalid_message
104
+ %(#{red "Is your config correct? You said:"}
105
+
106
+ #{File.read Boom.config.file}
107
+
108
+ #{cyan "Our survey says:"}
109
+
110
+ #{self.class.sample_config}
111
+
112
+ #{yellow "Go edit "} #{Boom.config.file + yellow(" and make it all better") }
113
+ ).gsub(/^ {8}/, '') # strip the first eight spaces of every line
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,7 @@
1
+ unless Symbol.method_defined?(:to_proc)
2
+ class Symbol
3
+ def to_proc
4
+ Proc.new { |obj, *args| obj.send(self, *args) }
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,72 @@
1
+ # coding: utf-8
2
+
3
+ # The representation of the base unit in boom. An Item contains just a name and
4
+ # a value. It doesn't know its parent relationship explicitly; the parent List
5
+ # object instead knows which Items it contains.
6
+ #
7
+ module Boom
8
+ class Item
9
+
10
+ # Public: the String name of the Item
11
+ attr_accessor :name
12
+
13
+ # Public: the String value of the Item
14
+ attr_accessor :value
15
+
16
+ # Public: creates a new Item object.
17
+ #
18
+ # name - the String name of the Item
19
+ # value - the String value of the Item
20
+ #
21
+ # Examples
22
+ #
23
+ # Item.new("github", "https://github.com")
24
+ #
25
+ # Returns the newly initialized Item.
26
+ def initialize(name,value)
27
+ @name = name
28
+ @value = value
29
+ end
30
+
31
+ # Public: the shortened String name of the Item. Truncates with ellipses if
32
+ # larger.
33
+ #
34
+ # Examples
35
+ #
36
+ # item = Item.new("github's home page","https://github.com")
37
+ # item.short_name
38
+ # # => 'github's home p…'
39
+ #
40
+ # item = Item.new("github","https://github.com")
41
+ # item.short_name
42
+ # # => 'github'
43
+ #
44
+ # Returns the shortened name.
45
+ def short_name
46
+ name.length > 15 ? "#{name[0..14]}…" : name[0..14]
47
+ end
48
+
49
+ # Public: the amount of consistent spaces to pad based on Item#short_name.
50
+ #
51
+ # Returns a String of spaces.
52
+ def spacer
53
+ name.length > 15 ? '' : ' '*(15-name.length+1)
54
+ end
55
+
56
+ # Public: only return url part of value - if no url has been
57
+ # detected returns value.
58
+ #
59
+ # Returns a String which preferably is a URL.
60
+ def url
61
+ @url ||= value.split(/\s+/).detect { |v| v =~ %r{\A[a-z0-9]+:\S+}i } || value
62
+ end
63
+
64
+ # Public: creates a Hash for this Item.
65
+ #
66
+ # Returns a Hash of its data.
67
+ def to_hash
68
+ { @name => @value }
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,100 @@
1
+ # coding: utf-8
2
+
3
+ # The List contains many Items. They exist as buckets in which to categorize
4
+ # individual Items. The relationship is maintained in a simple array on the
5
+ # List-level.
6
+ #
7
+ module Boom
8
+ class List
9
+
10
+ # Public: creates a new List instance in-memory.
11
+ #
12
+ # name - The name of the List. Fails if already used.
13
+ #
14
+ # Returns the unpersisted List instance.
15
+ def initialize(name)
16
+ @items = []
17
+ @name = name
18
+ end
19
+
20
+ # Public: accesses the in-memory JSON representation.
21
+ #
22
+ # Returns a Storage instance.
23
+ def self.storage
24
+ Boom.storage
25
+ end
26
+
27
+ # Public: lets you access the array of items contained within this List.
28
+ #
29
+ # Returns an Array of Items.
30
+ attr_accessor :items
31
+
32
+ # Public: the name of the List.
33
+ #
34
+ # Returns the String name.
35
+ attr_accessor :name
36
+
37
+ # Public: associates an Item with this List. If the item name is already
38
+ # defined, then the value will be replaced
39
+ #
40
+ # item - the Item object to associate with this List.
41
+ #
42
+ # Returns the current set of items.
43
+ def add_item(item)
44
+ delete_item(item.name) if find_item(item.name)
45
+ @items << item
46
+ end
47
+
48
+ # Public: finds any given List by name.
49
+ #
50
+ # name - String name of the list to search for
51
+ #
52
+ # Returns the first instance of List that it finds.
53
+ def self.find(name)
54
+ storage.lists.find { |list| list.name == name }
55
+ end
56
+
57
+ # Public: deletes a List by name.
58
+ #
59
+ # name - String name of the list to delete
60
+ #
61
+ # Returns whether one or more lists were removed.
62
+ def self.delete(name)
63
+ previous = storage.lists.size
64
+ storage.lists = storage.lists.reject { |list| list.name == name }
65
+ previous != storage.lists.size
66
+ end
67
+
68
+ # Public: deletes an Item by name.
69
+ #
70
+ # name - String name of the item to delete
71
+ #
72
+ # Returns whether an item was removed.
73
+ def delete_item(name)
74
+ previous = items.size
75
+ items.reject! { |item| item.name == name}
76
+ previous != items.size
77
+ end
78
+
79
+ # Public: finds an Item by name. If the name is typically truncated, also
80
+ # allow a search based on that truncated name.
81
+ #
82
+ # name - String name of the Item to find
83
+ #
84
+ # Returns the found item
85
+ def find_item(name)
86
+ items.find do |item|
87
+ item.name == name ||
88
+ item.short_name.gsub('…','') == name.gsub('…','')
89
+ end
90
+ end
91
+
92
+ # Public: a Hash representation of this List.
93
+ #
94
+ # Returns a Hash of its own data and its child Items.
95
+ def to_hash
96
+ { name => items.collect(&:to_hash) }
97
+ end
98
+
99
+ end
100
+ end
@@ -0,0 +1,13 @@
1
+ module Boom
2
+ module Output
3
+ # Public: prints any given string.
4
+ #
5
+ # s = String output
6
+ #
7
+ # Prints to STDOUT and returns. This method exists to standardize output
8
+ # and for easy mocking or overriding.
9
+ def output(s)
10
+ puts(s)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,103 @@
1
+ # coding: utf-8
2
+
3
+ # Platform is a centralized point to shell out platform specific functionality
4
+ # like clipboard access or commands to open URLs.
5
+ #
6
+ #
7
+ # Clipboard is a centralized point to shell out to each individual platform's
8
+ # clipboard, pasteboard, or whatever they decide to call it.
9
+ #
10
+ module Boom
11
+ class Platform
12
+ class << self
13
+ # Public: tests if currently running on darwin.
14
+ #
15
+ # Returns true if running on darwin (MacOS X), else false
16
+ def darwin?
17
+ !!(RUBY_PLATFORM =~ /darwin/)
18
+ end
19
+
20
+ # Public: tests if currently running on windows.
21
+ #
22
+ # Apparently Windows RUBY_PLATFORM can be 'win32' or 'mingw32'
23
+ #
24
+ # Returns true if running on windows (win32/mingw32), else false
25
+ def windows?
26
+ !!(RUBY_PLATFORM =~ /mswin|mingw/)
27
+ end
28
+
29
+ # Public: returns the command used to open a file or URL
30
+ # for the current platform.
31
+ #
32
+ # Currently only supports MacOS X and Linux with `xdg-open`.
33
+ #
34
+ # Returns a String with the bin
35
+ def open_command
36
+ if darwin?
37
+ 'open'
38
+ elsif windows?
39
+ 'start'
40
+ else
41
+ 'xdg-open'
42
+ end
43
+ end
44
+
45
+ # Public: opens a given Item's value in the browser. This
46
+ # method is designed to handle multiple platforms.
47
+ #
48
+ # Returns a String of the Item value.
49
+ def open(item)
50
+ unless windows?
51
+ system("#{open_command} '#{item.url.gsub("\'","'\\\\''")}'")
52
+ else
53
+ system("#{open_command} #{item.url.gsub("\'","'\\\\''")}")
54
+ end
55
+
56
+ item.value
57
+ end
58
+
59
+ # Public: returns the command used to copy a given Item's value to the
60
+ # clipboard for the current platform.
61
+ #
62
+ # Returns a String with the bin
63
+ def copy_command
64
+ if darwin?
65
+ 'pbcopy'
66
+ elsif windows?
67
+ 'clip'
68
+ else
69
+ 'xclip -selection clipboard'
70
+ end
71
+ end
72
+
73
+ # Public: copies a given Item's value to the clipboard. This method is
74
+ # designed to handle multiple platforms.
75
+ #
76
+ # Returns the String value of the Item.
77
+ def copy(item)
78
+ IO.popen(copy_command,"w") {|cc| cc.write(item.value)}
79
+ item.value
80
+ end
81
+
82
+ # Public: opens the JSON file in an editor for you to edit. Uses the
83
+ # $EDITOR environment variable, or %EDITOR% on Windows for editing.
84
+ # This method is designed to handle multiple platforms.
85
+ # If $EDITOR is nil, try to open using the open_command.
86
+ #
87
+ # Returns a String with a helpful message.
88
+ def edit(json_file)
89
+ unless $EDITOR.nil?
90
+ unless windows?
91
+ system("`echo $EDITOR` #{json_file} &")
92
+ else
93
+ system("start %EDITOR% #{json_file}")
94
+ end
95
+ else
96
+ system("#{open_command} #{json_file}")
97
+ end
98
+
99
+ "Make your edits, and do be sure to save."
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,47 @@
1
+ module Boom
2
+ module Remote
3
+ include Output
4
+ include Color
5
+
6
+ def allowed_storage_types
7
+ [Boom::Storage::Gist, Boom::Storage::Mongodb, Boom::Storage::Redis]
8
+ end
9
+
10
+ # Returns true if the user is using a sensible seeming storage backend
11
+ # Params storage, the current storage instance
12
+ # else exits with a warning if not
13
+ def allowed? storage
14
+ return true if Boom.local?
15
+ return true if allowed_storage_types.include? storage.class
16
+
17
+ output error_message storage
18
+ false
19
+ end
20
+
21
+ def error_message storage
22
+ %(
23
+ #{red("<<----BOOOOOM!!!----->>>> ")} (as in explosion, rather than fast)
24
+ You probably don't want to use the #{storage.class} storage whilst
25
+ using boom in remote mode. Your config looks akin to:
26
+
27
+ #{red File.read Boom.config.file}
28
+
29
+ but things might be better with something a little more like:
30
+
31
+ #{cyan Boom::Storage::Redis.sample_config}
32
+
33
+ or
34
+
35
+ #{cyan Boom::Storage::Mongodb.sample_config}
36
+
37
+ Now head yourself on over to #{yellow Boom.config.file}
38
+ and edit some goodness into it
39
+
40
+ Meanwhile, please enjoy your ordinary boom service:
41
+ ___________________________________________________
42
+
43
+ ).gsub(/^ {8}/, '')
44
+ end
45
+ extend self
46
+ end
47
+ end