strobe 0.0.1 → 0.0.2

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.
Files changed (42) hide show
  1. data/bin/strobe +2 -12
  2. data/lib/strobe.rb +35 -88
  3. data/lib/strobe/association.rb +86 -0
  4. data/lib/strobe/cli.rb +39 -53
  5. data/lib/strobe/cli/action.rb +131 -0
  6. data/lib/strobe/cli/actions.rb +103 -0
  7. data/lib/strobe/cli/settings.rb +62 -0
  8. data/lib/strobe/collection.rb +53 -0
  9. data/lib/strobe/connection.rb +91 -0
  10. data/lib/strobe/resource/base.rb +235 -0
  11. data/lib/strobe/resource/collection.rb +50 -0
  12. data/lib/strobe/resource/singleton.rb +18 -0
  13. data/lib/strobe/resources/account.rb +12 -0
  14. data/lib/strobe/resources/application.rb +129 -0
  15. data/lib/strobe/resources/me.rb +11 -0
  16. data/lib/strobe/resources/signup.rb +27 -0
  17. data/lib/strobe/resources/team.rb +13 -0
  18. data/lib/strobe/resources/user.rb +11 -0
  19. data/lib/strobe/validations.rb +118 -0
  20. metadata +50 -124
  21. data/.gitignore +0 -5
  22. data/Gemfile +0 -4
  23. data/Gemfile.lock +0 -69
  24. data/Rakefile +0 -36
  25. data/features/1_sign_up.feature +0 -16
  26. data/features/2_deploying.feature +0 -35
  27. data/features/3_deploying_sproutcore_apps.feature +0 -19
  28. data/features/step_definitions/cli_steps.rb +0 -8
  29. data/features/step_definitions/deploying_steps.rb +0 -58
  30. data/features/step_definitions/sign_up.rb +0 -74
  31. data/features/support/helpers.rb +0 -104
  32. data/features/support/strobe.rb +0 -57
  33. data/lib/strobe/account.rb +0 -67
  34. data/lib/strobe/deploy.rb +0 -131
  35. data/lib/strobe/errors.rb +0 -12
  36. data/lib/strobe/http.rb +0 -94
  37. data/lib/strobe/server.rb +0 -13
  38. data/lib/strobe/settings.rb +0 -56
  39. data/lib/strobe/ui.rb +0 -81
  40. data/lib/strobe/user.rb +0 -9
  41. data/lib/strobe/version.rb +0 -3
  42. data/strobe.gemspec +0 -35
data/bin/strobe CHANGED
@@ -1,14 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
+ require 'strobe'
2
3
 
3
- require "strobe"
4
-
5
- begin
6
- Strobe::CLI.start
7
- rescue Strobe::Error => e
8
- Strobe.ui.error e.message
9
- Strobe.ui.error e.backtrace.join("\n") if ENV["STROBE_DEBUG"]
10
- exit e.status_code
11
- rescue Interrupt
12
- Strobe.ui.error "\nQuitting..."
13
- exit 1
14
- end
4
+ Strobe::CLI.start
@@ -1,100 +1,47 @@
1
- require "pathname"
2
- require "yaml"
3
-
4
- class Strobe
5
- class << self
6
-
7
- # this isn't currently needed, but why start with globals when you could
8
- # just as easily start with a singleton instance, which may be helpful
9
- # later
10
- def main
11
- @main ||= new
12
- end
13
-
14
- def ui
15
- main.ui
16
- end
17
-
18
- def ui=(ui)
19
- main.ui = ui
20
- end
21
-
22
- def root
23
- main.root
24
- end
25
-
26
- def app_root
27
- main.app_root
28
- end
29
-
30
- def account
31
- main.account
32
- end
33
-
34
- def settings
35
- main.settings
36
- end
37
-
38
- def config_dir
39
- main.config_dir
40
- end
41
-
42
- def local_config_dir
43
- main.local_config_dir
44
- end
45
- end
46
-
47
- attr_writer :ui
48
-
49
- def ui
50
- @ui ||= UI::Basic.new
1
+ require 'base64'
2
+ require 'active_model'
3
+ require 'active_support/concern'
4
+ require 'active_support/core_ext/hash/deep_merge'
5
+ require 'active_support/core_ext/hash/reverse_merge'
6
+ require 'active_support/core_ext/hash/indifferent_access'
7
+ require 'active_support/core_ext/string/inflections'
8
+
9
+ module Strobe
10
+ autoload :Association, 'strobe/association'
11
+ autoload :CLI, 'strobe/cli'
12
+ autoload :Collection, 'strobe/collection'
13
+ autoload :Connection, 'strobe/connection'
14
+ autoload :Validations, 'strobe/validations'
15
+
16
+ module Resource
17
+ autoload :Base, 'strobe/resource/base'
18
+ autoload :Collection, 'strobe/resource/collection'
19
+ autoload :Singleton, 'strobe/resource/singleton'
51
20
  end
52
21
 
53
- def root
54
- sproutcore = "#{app_root}/tmp/build"
55
- File.directory?(sproutcore) ? sproutcore : app_root
22
+ # Resources
23
+ module Resources
24
+ autoload :Account, 'strobe/resources/account'
25
+ autoload :Application, 'strobe/resources/application'
26
+ autoload :Me, 'strobe/resources/me'
27
+ autoload :Signup, 'strobe/resources/signup'
28
+ autoload :Team, 'strobe/resources/team'
29
+ autoload :User, 'strobe/resources/user'
56
30
  end
57
31
 
58
- def app_root
59
- @app_root ||= Pathname.new(Dir.pwd)
60
- end
32
+ # Errors
33
+ class StrobeError < StandardError ; end
34
+ class UnauthenticatedError < StrobeError ; end
35
+ class ResourceNotFoundError < StrobeError ; end
61
36
 
62
- def config_dir
63
- @config_dir ||= begin
64
- dir = Pathname.new(File.join(Strobe.user_home, ".strobe"))
65
- FileUtils.mkdir_p(dir) unless dir.exist?
66
- dir
67
- end
37
+ def self.connection
38
+ @connection
68
39
  end
69
40
 
70
- def local_config_dir
71
- @local_config_dir ||= begin
72
- dir = Pathname.new(File.join(app_root, ".strobe"))
73
- FileUtils.mkdir_p(dir) unless dir.exist?
74
- dir
75
- end
41
+ def self.connection=(connection)
42
+ @connection = connection
76
43
  end
77
44
 
78
- def settings
79
- @settings ||= Settings.new
80
- end
81
-
82
- autoload :Account, "strobe/account"
83
- autoload :CLI, "strobe/cli"
84
- autoload :Deploy, "strobe/deploy"
85
- autoload :Error, "strobe/errors"
86
- autoload :HTTP, "strobe/http"
87
- autoload :Server, "strobe/server"
88
- autoload :Settings, "strobe/settings"
89
- autoload :UI, "strobe/ui"
90
- autoload :User, "strobe/user"
91
- autoload :Version, "strobe/version"
92
-
93
- # ERRORS
94
- autoload :AccountError, "strobe/errors"
95
- autoload :ApplicationError, "strobe/errors"
96
-
97
- private
98
45
  # sadly, copied from Rubygems
99
46
  def self.user_home
100
47
  unless RUBY_VERSION > '1.9' then
@@ -0,0 +1,86 @@
1
+ module Strobe
2
+ class Association
3
+ attr_reader :source, :name, :cardinality, :options
4
+
5
+ def initialize(source, cardinality, name, options)
6
+ @source = source
7
+ @cardinality = cardinality
8
+ @name = name.to_sym
9
+ @options = options
10
+ end
11
+
12
+ def target_name
13
+ 'Strobe::Resources::' + name.to_s.classify
14
+ end
15
+
16
+ def target
17
+ @target ||= target_name.constantize
18
+ end
19
+
20
+ def collection?
21
+ cardinality == :n
22
+ end
23
+
24
+ def autoload?
25
+ !options.key?(:autoload) || options[:autoload]
26
+ end
27
+
28
+ def include?
29
+ options[:include]
30
+ end
31
+
32
+ def reader
33
+ ruby = []
34
+ ruby << "def #{name}"
35
+
36
+ if autoload? && collection?
37
+
38
+ ruby << " @__#{name} ||= Strobe::Collection.new( " \
39
+ " #{target_name}, '#{source.singular_resource_name}_id' " \
40
+ " => self[:id] ) if self[:id]"
41
+
42
+ elsif autoload?
43
+
44
+ ruby << " return @__#{name} if @__#{name}"
45
+ ruby << " return nil unless self[:#{name}_id]"
46
+ ruby << " @__#{name} = #{target_name}.get( self[:#{name}_id] )"
47
+
48
+ end
49
+
50
+ ruby << " @__#{name}"
51
+
52
+ ruby << "end"
53
+ ruby.join("\n")
54
+ end
55
+
56
+ def writer
57
+ ruby = []
58
+ ruby << "def #{name}=(val)"
59
+
60
+ if collection?
61
+
62
+ ruby << " raise NotImplementedError"
63
+
64
+ else
65
+
66
+ ruby << " if val"
67
+ ruby << " if val.is_a?(Hash)"
68
+ ruby << " val = #{target_name}.new(val)"
69
+ ruby << " elsif !val.is_a?(#{target_name})"
70
+ ruby << " raise 'fail'"
71
+ ruby << " end"
72
+
73
+ ruby << " self[:#{name}_id] = val[:id]" if autoload?
74
+ ruby << " @__#{name} = val"
75
+ ruby << " else"
76
+ ruby << " self[:#{name}_id] = nil" if autoload?
77
+ ruby << " @__#{name} = nil"
78
+ ruby << " end"
79
+
80
+ end
81
+
82
+ ruby << "end"
83
+ ruby.join("\n")
84
+ end
85
+ end
86
+ end
@@ -1,78 +1,64 @@
1
- require "thor"
1
+ require 'thor'
2
+ require 'pathname'
3
+ require 'fileutils'
2
4
 
3
- class Strobe
5
+ module Strobe
4
6
  class CLI < Thor
5
- check_unknown_options!
7
+ autoload :Action, 'strobe/cli/action'
8
+ autoload :Settings, 'strobe/cli/settings'
6
9
 
7
- class_option "no-color", :type => :boolean, :banner => "Disable colorization in output"
8
- class_option "path", :type => :string, :banner => "The path to your application"
10
+ def self.start(*)
11
+ super
12
+ rescue Strobe::StrobeError => e
13
+ raise if $STROBE_BACKTRACE
14
+ abort "[ERROR] #{e.message}"
15
+ end
16
+
17
+ class_option "backtrace", :type => :boolean, :banner => "Show a backtrace in case of an exception"
9
18
 
10
19
  def initialize(*)
11
20
  super
12
21
 
13
- opts = {"path" => Strobe.root}.merge(options)
14
- self.options = Thor::CoreExt::HashWithIndifferentAccess.new(opts)
15
-
16
- use_shell = options["no-color"] ? Thor::Shell::Basic.new : shell
17
- Strobe.ui = UI::Shell.new(use_shell)
22
+ $STROBE_BACKTRACE = true if options[:backtrace]
23
+ _settings.connect!
18
24
  end
19
25
 
20
- desc "signup", "sign up for a new Strobe account"
26
+ # Load the CLI actions
27
+ require "strobe/cli/actions"
28
+
29
+ desc "signup", "signup for a new Strobe account"
21
30
  def signup
22
- Account.signup
31
+ _run :signup
32
+ end
33
+
34
+ desc "login", "register this computer with an existing Strobe account"
35
+ def login
36
+ _run :login
23
37
  end
24
38
 
25
39
  desc "deploy", "deploy your application to Strobe"
40
+ method_option "path", :type => :string, :banner => "The path to the application"
26
41
  def deploy
27
- Deploy.new(options[:path]).deploy
28
- end
42
+ path = options[:path] || Dir.pwd
43
+ config = Settings.new(Pathname.new(path).join(".strobe/config"))
29
44
 
30
- desc "preview", "preview your application locally"
31
- def preview
32
- Server.new(options[:path]).start
45
+ _run :deploy, :config => config, :path => path
33
46
  end
34
47
 
35
- def help(command)
36
- case command
37
- when "gemfile" then command = "gemfile.5"
38
- when nil then command = "bundle"
39
- else command = "bundle-#{cli}"
40
- end
41
-
42
- root = File.expand_path("../man", __FILE__)
43
-
44
- if manpages.include?(command)
45
- if have_groff?
46
- groff = "groff -Wall -mtty-char -mandoc -Tascii"
47
- pager = ENV['MANPAGER'] || ENV['PAGER'] || 'more'
48
+ private
48
49
 
49
- Kernel.exec "#{groff} #{root}/#{command} | #{pager}"
50
- else
51
- puts File.read("#{root}/#{command}.txt")
52
- end
53
- else
54
- super
55
- end
50
+ def _init_application
51
+ path = options[:path]
52
+ dir = Pathname.new(path).join(".strobe")
53
+ FileUtils.mkdir_p dir
56
54
  end
57
55
 
58
- private
59
- def manpages
60
- man_root = File.expand_path("../man", __FILE__)
61
- return [] unless File.directory?(man_root)
62
-
63
- man_pages = []
64
- Dir["#{man_root}/*"].each do |file|
65
- base = File.basename(file)
66
- next if base.include?(".")
67
- man_pages << base
68
- end
69
- man_pages
56
+ def _run(name, opts = {})
57
+ Action.run name, _settings, opts
70
58
  end
71
59
 
72
- def have_groff?
73
- `which groff 2>#{NULL}`
74
- $? == 0
60
+ def _settings
61
+ @settings ||= Settings.new
75
62
  end
76
63
  end
77
64
  end
78
-
@@ -0,0 +1,131 @@
1
+ require 'highline'
2
+
3
+ module Strobe
4
+ class CLI::Action
5
+ def self.run(action, settings, options = {})
6
+ success = false
7
+ klass = action.to_s.classify + 'Action'
8
+ klass = CLI::Actions.const_get(klass)
9
+
10
+ until success == true
11
+ action = klass.new(settings, options)
12
+ action.steps
13
+ success = !action.restart
14
+ end
15
+ end
16
+
17
+ include Resources
18
+
19
+ attr_reader :actions, :settings, :restart, :options
20
+
21
+ def initialize(settings, options)
22
+ @settings = settings
23
+ @options = options
24
+ @highline = HighLine.new
25
+ @resource = nil
26
+
27
+ # State
28
+ @in_group = false
29
+ @restart = false
30
+ end
31
+
32
+ def resource(resource = nil)
33
+ @resource = resource if resource
34
+ @resource
35
+ end
36
+
37
+ def say(what)
38
+ puts what
39
+ end
40
+
41
+ def agree(msg, *args)
42
+ @highline.agree(msg, *args) do |q|
43
+ next unless STDIN.tty? # For testing
44
+ q.readline = true
45
+ end
46
+ end
47
+
48
+ def ask(key, options = {})
49
+ input key, options do |msg|
50
+ resp = @highline.ask msg do |q|
51
+ next unless STDIN.tty? # For testing
52
+ q.readline = true
53
+ end
54
+ end
55
+ end
56
+
57
+ def password(key, options = {})
58
+ input key, options do |msg|
59
+ @highline.ask msg do |q|
60
+ next unless STDIN.tty? # For testing
61
+ q.echo = '*'
62
+ end
63
+ end
64
+ end
65
+
66
+ def choose
67
+ @highline.choose do |menu|
68
+ yield menu
69
+ end
70
+ end
71
+
72
+ def group(options = {}, &blk)
73
+ case
74
+ when key = options[:validate]
75
+ validation_group(key, &blk)
76
+ else
77
+ yield if block_given?
78
+ end
79
+ end
80
+
81
+ def save(opts = {})
82
+ if resource.save
83
+ yield
84
+ else
85
+ display_errors
86
+ if opts[:on_error] == :restart
87
+ @restart = true
88
+ end
89
+ end
90
+ end
91
+
92
+ def run(action, opts = {})
93
+ CLI::Action.run(action, settings, opts)
94
+ end
95
+
96
+ private
97
+
98
+ def input(key, options)
99
+ into = options[:into] || key
100
+
101
+ validation_group into do
102
+ msg = (key.to_s.humanize + ': ').ljust(25)
103
+ resource[into] = yield msg
104
+ end
105
+ end
106
+
107
+ def validation_group(resource_key)
108
+ return yield if @in_group
109
+
110
+ begin
111
+ @in_group = true
112
+ while true
113
+ yield
114
+
115
+ break if resource.valid_attribute?(resource_key)
116
+
117
+ display_errors
118
+ end
119
+ ensure
120
+ @in_group = false
121
+ end
122
+ end
123
+
124
+ def display_errors
125
+ resource.errors.each do |k, msg|
126
+ key = k.to_s.split('.').last
127
+ say "[ERROR] #{key.humanize} #{msg}"
128
+ end
129
+ end
130
+ end
131
+ end