cosm 0.0.1

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.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright © Heroku 2008 - 2012
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,8 @@
1
+ Cosm CLI
2
+ ========
3
+
4
+ A Cosm CLI which currently allows you to connect to the tcp socket server and subscribe to a datastream
5
+
6
+ [![Build Status](https://secure.travis-ci.org/levent/cosm.png)](http://travis-ci.org/levent/cosm)
7
+ [![Dependency Status](https://gemnasium.com/levent/cosm.png)](https://gemnasium.com/levent/cosm)
8
+
data/bin/cosm ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ begin
5
+ # resolve bin path, ignoring symlinks
6
+ require "pathname"
7
+ bin_file = Pathname.new(__FILE__).realpath
8
+
9
+ # add self to libpath
10
+ $:.unshift File.expand_path("../../lib", bin_file)
11
+
12
+ # start up the CLI
13
+ require "cosm/cli"
14
+ Cosm::CLI.start(*ARGV)
15
+ rescue Interrupt
16
+ `stty icanon echo`
17
+ puts("\n ! Command cancelled.")
18
+ end
data/lib/cosm/cli.rb ADDED
@@ -0,0 +1,12 @@
1
+ require "cosm"
2
+ require "cosm/command"
3
+
4
+ class Cosm::CLI
5
+
6
+ def self.start(*args)
7
+ command = args.shift.strip rescue "help"
8
+ Cosm::Command.load
9
+ Cosm::Command.run(command, args)
10
+ end
11
+
12
+ end
@@ -0,0 +1,148 @@
1
+ require "fileutils"
2
+ require "cosm/command"
3
+
4
+ class Cosm::Command::Base
5
+
6
+ def self.namespace
7
+ self.to_s.split("::").last.downcase
8
+ end
9
+
10
+ attr_reader :args
11
+ attr_reader :options
12
+
13
+ def initialize(args=[], options={})
14
+ @args = args
15
+ @options = options
16
+ end
17
+
18
+ protected
19
+
20
+ def self.inherited(klass)
21
+ unless klass == Cosm::Command::Base
22
+ help = extract_help_from_caller(caller.first)
23
+
24
+ Cosm::Command.register_namespace(
25
+ :name => klass.namespace,
26
+ :description => help.first
27
+ )
28
+ end
29
+ end
30
+
31
+ def self.method_added(method)
32
+ return if self == Cosm::Command::Base
33
+ return if private_method_defined?(method)
34
+ return if protected_method_defined?(method)
35
+
36
+ help = extract_help_from_caller(caller.first)
37
+ resolved_method = (method.to_s == "index") ? nil : method.to_s
38
+ command = [ self.namespace, resolved_method ].compact.join(":")
39
+ banner = extract_banner(help) || command
40
+
41
+ Cosm::Command.register_command(
42
+ :klass => self,
43
+ :method => method,
44
+ :namespace => self.namespace,
45
+ :command => command,
46
+ :banner => banner.strip,
47
+ :help => help.join("\n"),
48
+ :summary => extract_summary(help),
49
+ :description => extract_description(help),
50
+ :options => extract_options(help)
51
+ )
52
+ end
53
+
54
+ def self.alias_command(new, old)
55
+ raise "no such command: #{old}" unless Cosm::Command.commands[old]
56
+ Cosm::Command.command_aliases[new] = old
57
+ end
58
+
59
+ #
60
+ # Parse the caller format and identify the file and line number as identified
61
+ # in : http://www.ruby-doc.org/core/classes/Kernel.html#M001397. This will
62
+ # look for a colon followed by a digit as the delimiter. The biggest
63
+ # complication is windows paths, which have a color after the drive letter.
64
+ # This regex will match paths as anything from the beginning to a colon
65
+ # directly followed by a number (the line number).
66
+ #
67
+ def self.extract_help_from_caller(line)
68
+ # pull out of the caller the information for the file path and line number
69
+ if line =~ /^(.+?):(\d+)/
70
+ extract_help($1, $2)
71
+ else
72
+ raise("unable to extract help from caller: #{line}")
73
+ end
74
+ end
75
+
76
+ def self.extract_help(file, line_number)
77
+ buffer = []
78
+ lines = Cosm::Command.files[file]
79
+
80
+ (line_number.to_i-2).downto(0) do |i|
81
+ line = lines[i]
82
+ case line[0..0]
83
+ when ""
84
+ when "#"
85
+ buffer.unshift(line[1..-1])
86
+ else
87
+ break
88
+ end
89
+ end
90
+
91
+ buffer
92
+ end
93
+
94
+ def self.extract_banner(help)
95
+ help.first
96
+ end
97
+
98
+ def self.extract_summary(help)
99
+ extract_description(help).split("\n")[2].to_s.split("\n").first
100
+ end
101
+
102
+ def self.extract_description(help)
103
+ help.reject do |line|
104
+ line =~ /^\s+-(.+)#(.+)/
105
+ end.join("\n")
106
+ end
107
+
108
+ def self.extract_options(help)
109
+ help.select do |line|
110
+ line =~ /^\s+-(.+)#(.+)/
111
+ end.inject({}) do |hash, line|
112
+ description = line.split("#", 2).last
113
+ long = line.match(/--([A-Za-z\- ]+)/)[1].strip
114
+ short = line.match(/-([A-Za-z ])[ ,]/) && $1 && $1.strip
115
+ hash.update(long.split(" ").first => { :desc => description, :short => short, :long => long })
116
+ end
117
+ end
118
+
119
+ def current_command
120
+ Cosm::Command.current_command
121
+ end
122
+
123
+ def extract_option(key)
124
+ options[key.dup.gsub('-','').to_sym]
125
+ end
126
+
127
+ def invalid_arguments
128
+ Cosm::Command.invalid_arguments
129
+ end
130
+
131
+ def shift_argument
132
+ Cosm::Command.shift_argument
133
+ end
134
+
135
+ def validate_arguments!
136
+ Cosm::Command.validate_arguments!
137
+ end
138
+
139
+ def escape(value)
140
+ cosm.escape(value)
141
+ end
142
+ end
143
+
144
+ module Cosm::Command
145
+ unless const_defined?(:BaseWithApp)
146
+ BaseWithApp = Base
147
+ end
148
+ end
@@ -0,0 +1,121 @@
1
+ # list commands and display help
2
+ #
3
+ class Cosm::Command::Help < Cosm::Command::Base
4
+
5
+ PRIMARY_NAMESPACES = %w( subscribe )
6
+
7
+ # help [COMMAND]
8
+ #
9
+ # list available commands or display help for a specific command
10
+ #
11
+ #Examples:
12
+ #
13
+ # $ cosm help
14
+ # Usage: cosm COMMAND [--key API_KEY] [command-specific-options]
15
+ #
16
+ # Primary help topics, type "cosm help TOPIC" for more details:
17
+ #
18
+ # subscribe # subscribe to a datastream
19
+ # ...
20
+ #
21
+ def index
22
+ if command = args.shift
23
+ help_for_command(command)
24
+ else
25
+ help_for_root
26
+ end
27
+ end
28
+
29
+ alias_command "-h", "help"
30
+ alias_command "--help", "help"
31
+
32
+ def self.usage_for_command(command)
33
+ command = new.send(:commands)[command]
34
+ "Usage: cosm #{command[:banner]}" if command
35
+ end
36
+
37
+ private
38
+
39
+ def commands_for_namespace(name)
40
+ Cosm::Command.commands.values.select do |command|
41
+ command[:namespace] == name && command[:command] != name
42
+ end
43
+ end
44
+
45
+ def namespaces
46
+ namespaces = Cosm::Command.namespaces
47
+ namespaces.delete("app")
48
+ namespaces
49
+ end
50
+
51
+ def commands
52
+ Cosm::Command.commands
53
+ end
54
+
55
+ def primary_namespaces
56
+ PRIMARY_NAMESPACES.map { |name| namespaces[name] }.compact
57
+ end
58
+
59
+ def additional_namespaces
60
+ (namespaces.values - primary_namespaces)
61
+ end
62
+
63
+ def summary_for_namespaces(namespaces)
64
+ size = (namespaces.map { |n| n[:name] }).map { |i| i.to_s.length }.sort.last
65
+ namespaces.sort_by {|namespace| namespace[:name]}.each do |namespace|
66
+ name = namespace[:name]
67
+ namespace[:description]
68
+ puts " %-#{size}s # %s" % [ name, namespace[:description] ]
69
+ end
70
+ end
71
+
72
+ def help_for_root
73
+ puts "Usage: cosm COMMAND [--key API_KEY] [command-specific-options]"
74
+ puts
75
+ puts "Primary help topics, type \"cosm help TOPIC\" for more details:"
76
+ puts
77
+ summary_for_namespaces(primary_namespaces)
78
+ puts
79
+ puts "Additional topics:"
80
+ puts
81
+ summary_for_namespaces(additional_namespaces)
82
+ puts
83
+ end
84
+
85
+ def help_for_namespace(name)
86
+ namespace_commands = commands_for_namespace(name)
87
+
88
+ unless namespace_commands.empty?
89
+ size = (namespace_commands.map { |c| c[:banner] }).map { |i| i.to_s.length }.sort.last
90
+ namespace_commands.sort_by { |c| c[:banner].to_s }.each do |command|
91
+ next if command[:help] =~ /DEPRECATED/
92
+ command[:summary]
93
+ puts " %-#{size}s # %s" % [ command[:banner], command[:summary] ]
94
+ end
95
+ end
96
+ end
97
+
98
+ def help_for_command(name)
99
+ if command_alias = Cosm::Command.command_aliases[name]
100
+ puts("Alias: #{name} is short for #{command_alias}")
101
+ name = command_alias
102
+ end
103
+ if command = commands[name]
104
+ puts "Usage: cosm #{command[:banner]}"
105
+
106
+ if command[:help].strip.length > 0
107
+ puts command[:help].split("\n")[1..-1].join("\n")
108
+ end
109
+ puts
110
+ end
111
+
112
+ if commands_for_namespace(name).size > 0
113
+ puts "Additional commands, type \"cosm help COMMAND\" for more details:"
114
+ puts
115
+ help_for_namespace(name)
116
+ puts
117
+ elsif command.nil?
118
+ puts "#{name} is not a cosm command. See `cosm help`."
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,62 @@
1
+ require 'cosm/command/base'
2
+ require 'socket'
3
+
4
+ # Subscribe to a datastream via the Cosm PAWS (Socket Server)
5
+ #
6
+ class Cosm::Command::Subscribe < Cosm::Command::Base
7
+
8
+ # subscribe
9
+ #
10
+ # connect to a tcp socket for a datastream
11
+ #
12
+ # -k, --key API_KEY # your api key
13
+ # -f, --feed FEED # the feed id
14
+ # -d, --datastream DATASTREAM # the datastream id
15
+ #
16
+ #Example:
17
+ #
18
+ # $ cosm subscribe -k ABCD1234 -f 504 -d 0
19
+ #
20
+ def index
21
+ api_key = options[:key]
22
+ feed_id = options[:feed]
23
+ datastream_id = options[:datastream]
24
+
25
+ validate_arguments!
26
+
27
+ unless api_key && feed_id && datastream_id
28
+ puts Cosm::Command::Help.usage_for_command("subscribe")
29
+ exit(1)
30
+ end
31
+
32
+ subscribe = "{\"method\":\"subscribe\", \"resource\":\"/feeds/#{feed_id}/datastreams/#{datastream_id}\", \"headers\":{\"X-ApiKey\":\"#{api_key}\"}}"
33
+ s = TCPSocket.new 'api.cosm.com', 8081
34
+ s.puts subscribe
35
+ while line = s.gets
36
+ parse_data(line, s)
37
+ end
38
+ s.close
39
+
40
+ # EventMachine.run {
41
+ # EventMachine::connect 'api.cosm.com', 8081, CosmSocket, options
42
+ # }
43
+ rescue Interrupt => e
44
+ puts "Closing connection"
45
+ s.close
46
+ raise e
47
+ end
48
+
49
+ alias_command "sub", "subscribe"
50
+
51
+ protected
52
+
53
+ def parse_data(string, socket)
54
+ puts(string)
55
+ if string =~ /"status":40/
56
+ socket.close
57
+ exit(1)
58
+ end
59
+ end
60
+
61
+ end
62
+
@@ -0,0 +1,23 @@
1
+ require "cosm/command/base"
2
+ require "cosm/version"
3
+
4
+ # display version
5
+ #
6
+ class Cosm::Command::Version < Cosm::Command::Base
7
+
8
+ # version
9
+ #
10
+ # show cosm client version
11
+ #
12
+ #Example:
13
+ #
14
+ # $ cosm version
15
+ # v0.0.1
16
+ #
17
+ def index
18
+ validate_arguments!
19
+
20
+ puts(Cosm::VERSION)
21
+ end
22
+
23
+ end
@@ -0,0 +1,168 @@
1
+ require 'cosm/version'
2
+ require "optparse"
3
+
4
+ module Cosm
5
+ module Command
6
+ class CommandFailed < RuntimeError; end
7
+
8
+ def self.load
9
+ Dir[File.join(File.dirname(__FILE__), "command", "*.rb")].each do |file|
10
+ require file
11
+ end
12
+ end
13
+
14
+ def self.commands
15
+ @@commands ||= {}
16
+ end
17
+
18
+ def self.command_aliases
19
+ @@command_aliases ||= {}
20
+ end
21
+
22
+ def self.files
23
+ @@files ||= Hash.new {|hash,key| hash[key] = File.readlines(key).map {|line| line.strip}}
24
+ end
25
+
26
+ def self.namespaces
27
+ @@namespaces ||= {}
28
+ end
29
+
30
+ def self.register_command(command)
31
+ commands[command[:command]] = command
32
+ end
33
+
34
+ def self.register_namespace(namespace)
35
+ namespaces[namespace[:name]] = namespace
36
+ end
37
+
38
+ def self.current_command
39
+ @current_command
40
+ end
41
+
42
+ def self.current_command=(new_current_command)
43
+ @current_command = new_current_command
44
+ end
45
+
46
+ def self.global_options
47
+ @global_options ||= []
48
+ end
49
+
50
+ def self.invalid_arguments
51
+ @invalid_arguments
52
+ end
53
+
54
+ def self.shift_argument
55
+ @invalid_arguments.shift.downcase rescue nil
56
+ end
57
+
58
+ def self.validate_arguments!
59
+ unless invalid_arguments.empty?
60
+ arguments = invalid_arguments.map {|arg| "\"#{arg}\""}
61
+ if arguments.length == 1
62
+ message = "Invalid argument: #{arguments.first}"
63
+ elsif arguments.length > 1
64
+ message = "Invalid arguments: "
65
+ message << arguments[0...-1].join(", ")
66
+ message << " and "
67
+ message << arguments[-1]
68
+ end
69
+ $stderr.puts(message)
70
+ run(current_command, ["--help"])
71
+ exit(1)
72
+ end
73
+ end
74
+
75
+ def self.warnings
76
+ @warnings ||= []
77
+ end
78
+
79
+ def self.display_warnings
80
+ unless warnings.empty?
81
+ $stderr.puts(warnings.map {|warning| " ! #{warning}"}.join("\n"))
82
+ end
83
+ end
84
+
85
+ def self.global_option(name, *args, &blk)
86
+ global_options << { :name => name, :args => args, :proc => blk }
87
+ end
88
+
89
+ global_option :key, "--key API_KEY", "-k"
90
+ global_option :help, "--help", "-h"
91
+
92
+ def self.prepare_run(cmd, args=[])
93
+ command = parse(cmd)
94
+
95
+ unless command
96
+ if %w( -v --version ).include?(cmd)
97
+ command = parse('version')
98
+ else
99
+ $stderr.puts(["`#{cmd}` is not a cosm command.", "See `cosm help` for a list of available commands."].join("\n"))
100
+ exit(1)
101
+ end
102
+ end
103
+
104
+ @current_command = cmd
105
+
106
+ opts = {}
107
+ invalid_options = []
108
+
109
+ parser = OptionParser.new do |parser|
110
+ # overwrite OptionParsers Officious['version'] to avoid conflicts
111
+ # see: https://github.com/ruby/ruby/blob/trunk/lib/optparse.rb#L814
112
+ parser.on("--version") do |value|
113
+ invalid_options << "--version"
114
+ end
115
+ global_options.each do |global_option|
116
+ parser.on(*global_option[:args]) do |value|
117
+ global_option[:proc].call(value) if global_option[:proc]
118
+ opts[global_option[:name]] = value
119
+ end
120
+ end
121
+ command[:options].each do |name, option|
122
+ parser.on("-#{option[:short]}", "--#{option[:long]}", option[:desc]) do |value|
123
+ opts[name.gsub("-", "_").to_sym] = value
124
+ end
125
+ end
126
+ end
127
+
128
+ begin
129
+ parser.order!(args) do |nonopt|
130
+ invalid_options << nonopt
131
+ end
132
+ rescue OptionParser::InvalidOption => ex
133
+ invalid_options << ex.args.first
134
+ retry
135
+ end
136
+
137
+ if opts[:help]
138
+ args.unshift cmd unless cmd =~ /^-.*/
139
+ cmd = "help"
140
+ command = parse(cmd)
141
+ end
142
+
143
+ args.concat(invalid_options)
144
+
145
+ @current_args = args
146
+ @current_options = opts
147
+ @invalid_arguments = invalid_options
148
+
149
+ [ command[:klass].new(args.dup, opts.dup), command[:method] ]
150
+ end
151
+
152
+ def self.run(cmd, arguments=[])
153
+ object, method = prepare_run(cmd, arguments.dup)
154
+ object.send(method)
155
+ rescue CommandFailed => e
156
+ $stderr.puts e.message
157
+ rescue OptionParser::ParseError
158
+ commands[cmd] ? run("help", [cmd]) : run("help")
159
+ ensure
160
+ display_warnings
161
+ end
162
+
163
+ def self.parse(cmd)
164
+ commands[cmd] || commands[command_aliases[cmd]]
165
+ end
166
+
167
+ end
168
+ end
@@ -0,0 +1,3 @@
1
+ module Cosm
2
+ VERSION = "0.0.1"
3
+ end
data/lib/cosm.rb ADDED
@@ -0,0 +1,2 @@
1
+ module Cosm
2
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cosm
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Levent Ali
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-06-09 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Cosm CLI
15
+ email: lebreeze@gmail.com
16
+ executables:
17
+ - cosm
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/cosm/cli.rb
22
+ - lib/cosm/command/base.rb
23
+ - lib/cosm/command/help.rb
24
+ - lib/cosm/command/subscribe.rb
25
+ - lib/cosm/command/version.rb
26
+ - lib/cosm/command.rb
27
+ - lib/cosm/version.rb
28
+ - lib/cosm.rb
29
+ - LICENSE
30
+ - README.md
31
+ - bin/cosm
32
+ homepage: https://github.com/levent/cosm
33
+ licenses:
34
+ - MIT
35
+ post_install_message:
36
+ rdoc_options: []
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ segments:
46
+ - 0
47
+ hash: 2524522414027022837
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ segments:
55
+ - 0
56
+ hash: 2524522414027022837
57
+ requirements: []
58
+ rubyforge_project:
59
+ rubygems_version: 1.8.23
60
+ signing_key:
61
+ specification_version: 3
62
+ summary: Provides a client to Cosm
63
+ test_files: []
64
+ has_rdoc: