appjam 0.1.0.pre6 → 0.1.0.pre9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/README.rdoc +1 -1
  2. data/bin/appjam +2 -7
  3. data/lib/appjam.rb +9 -1
  4. data/lib/appjam/command.rb +27 -0
  5. data/lib/appjam/generators/actions.rb +170 -0
  6. data/lib/appjam/generators/cli.rb +42 -0
  7. data/lib/appjam/generators/model.rb +51 -0
  8. data/lib/appjam/generators/project.rb +9 -6
  9. data/lib/appjam/generators/project/Classes/{users → contacts}/ApplicationFacade.h.tt +0 -0
  10. data/lib/appjam/generators/project/Classes/{users → contacts}/ApplicationFacade.m.tt +0 -0
  11. data/lib/appjam/generators/project/Classes/{users → contacts}/controller/CreateUserCommand.h.tt +0 -0
  12. data/lib/appjam/generators/project/Classes/{users → contacts}/controller/CreateUserCommand.m.tt +0 -0
  13. data/lib/appjam/generators/project/Classes/{users → contacts}/controller/DeleteUserCommand.h.tt +0 -0
  14. data/lib/appjam/generators/project/Classes/{users → contacts}/controller/DeleteUserCommand.m.tt +0 -0
  15. data/lib/appjam/generators/project/Classes/{users → contacts}/controller/GetUsersCommand.h.tt +0 -0
  16. data/lib/appjam/generators/project/Classes/{users → contacts}/controller/GetUsersCommand.m.tt +0 -0
  17. data/lib/appjam/generators/project/Classes/{users → contacts}/controller/StartupCommand.h.tt +0 -0
  18. data/lib/appjam/generators/project/Classes/{users → contacts}/controller/StartupCommand.m.tt +0 -0
  19. data/lib/appjam/generators/project/Classes/{users → contacts}/controller/UpdateUserCommand.h.tt +0 -0
  20. data/lib/appjam/generators/project/Classes/{users → contacts}/controller/UpdateUserCommand.m.tt +0 -0
  21. data/lib/appjam/generators/project/Classes/{users → contacts}/model/UserProxy.h.tt +0 -0
  22. data/lib/appjam/generators/project/Classes/{users → contacts}/model/UserProxy.m.tt +0 -0
  23. data/lib/appjam/generators/project/Classes/{users → contacts}/model/vo/UserVO.h.tt +0 -0
  24. data/lib/appjam/generators/project/Classes/{users → contacts}/model/vo/UserVO.m.tt +0 -0
  25. data/lib/appjam/generators/project/Classes/{users → contacts}/view/ContactsMediator.h.tt +0 -0
  26. data/lib/appjam/generators/project/Classes/{users → contacts}/view/ContactsMediator.m.tt +0 -0
  27. data/lib/appjam/generators/project/Classes/{users → contacts}/view/UserFormMediator.h.tt +0 -0
  28. data/lib/appjam/generators/project/Classes/{users → contacts}/view/UserFormMediator.m.tt +0 -0
  29. data/lib/appjam/generators/project/Classes/{users → contacts}/view/UserListMediator.h.tt +0 -0
  30. data/lib/appjam/generators/project/Classes/{users → contacts}/view/UserListMediator.m.tt +0 -0
  31. data/lib/appjam/generators/project/Classes/{users → contacts}/view/components/Contacts.h.tt +0 -0
  32. data/lib/appjam/generators/project/Classes/{users → contacts}/view/components/Contacts.m.tt +0 -0
  33. data/lib/appjam/generators/project/Classes/{users → contacts}/view/components/UserForm.h.tt +0 -0
  34. data/lib/appjam/generators/project/Classes/{users → contacts}/view/components/UserForm.m.tt +0 -0
  35. data/lib/appjam/generators/project/Classes/{users → contacts}/view/components/UserList.h.tt +0 -0
  36. data/lib/appjam/generators/project/Classes/{users → contacts}/view/components/UserList.m.tt +0 -0
  37. data/lib/appjam/generators/project/Contacts.xcodeproj/eiffel.pbxuser +185 -41
  38. data/lib/appjam/generators/project/Contacts.xcodeproj/eiffel.perspectivev3 +23 -22
  39. data/lib/appjam/generators/project/Contacts.xcodeproj/project.pbxproj +102 -102
  40. data/lib/appjam/version.rb +1 -1
  41. data/test/helper.rb +132 -0
  42. data/test/test_project_generator.rb +38 -0
  43. metadata +263 -56
  44. data/spec/appjam_spec.rb +0 -7
  45. data/spec/spec_helper.rb +0 -12
data/README.rdoc CHANGED
@@ -10,7 +10,7 @@ run command below in your favorite shell, appjam will generate your iphone app s
10
10
 
11
11
  $ gem install appjam --pre
12
12
 
13
- $ appjam User # Model name(like User)
13
+ $ appjam project contact
14
14
 
15
15
  == Contributing to appjam
16
16
 
data/bin/appjam CHANGED
@@ -7,11 +7,6 @@ unless $LOAD_PATH.include?(lib_dir)
7
7
  end
8
8
 
9
9
  require 'appjam'
10
- require File.expand_path(File.dirname(__FILE__) + '/../lib/appjam/generators/project')
10
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/appjam/generators/cli')
11
11
 
12
- begin
13
- Appjam::Generators::Project.start(ARGV)
14
- rescue => e
15
- STDERR.puts "Error: #{e}"
16
- exit -1
17
- end
12
+ Appjam::Generators::Cli.start(ARGV)
data/lib/appjam.rb CHANGED
@@ -40,6 +40,14 @@ module Appjam
40
40
  def add_generator(name, klass)
41
41
  mappings[name] = klass
42
42
  end
43
+
44
+ ##
45
+ # Load Global Actions and Component Actions then all files in +load_path+.
46
+ #
47
+ def load_components!
48
+ require 'appjam/generators/actions'
49
+ load_paths.flatten.each { |file| require file }
50
+ end
43
51
  end
44
52
  end # Generators
45
53
  end # IphoneMvc
@@ -47,4 +55,4 @@ end # IphoneMvc
47
55
  ##
48
56
  # We add our generators to Appjam::Genererator
49
57
  #
50
- Appjam::Generators.load_paths << Dir[File.dirname(__FILE__) + '/appjam/generators/project.rb']
58
+ Appjam::Generators.load_paths << Dir[File.dirname(__FILE__) + '/appjam/generators/{project,model}.rb']
@@ -0,0 +1,27 @@
1
+ require 'rbconfig'
2
+
3
+ module Appjam
4
+ ##
5
+ # This method return the correct location of appjam bin or
6
+ # exec it using Kernel#system with the given args
7
+ #
8
+ def self.bin(*args)
9
+ @_appjam_bin ||= [self.ruby_command, File.expand_path("../../../bin/appjam", __FILE__)]
10
+ args.empty? ? @_appjam_bin : system(args.unshift(@_appjam_bin).join(" "))
11
+ end
12
+
13
+ ##
14
+ # Return the path to the ruby interpreter taking into account multiple
15
+ # installations and windows extensions.
16
+ #
17
+ def self.ruby_command
18
+ @ruby_command ||= begin
19
+ ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
20
+ ruby << Config::CONFIG['EXEEXT']
21
+
22
+ # escape string in case path to ruby executable contain spaces.
23
+ ruby.sub!(/.*\s.*/m, '"\&"')
24
+ ruby
25
+ end
26
+ end
27
+ end # Appjam
@@ -0,0 +1,170 @@
1
+ module Appjam
2
+ module Generators
3
+ class AppRootNotFound < RuntimeError; end
4
+
5
+ module Actions
6
+
7
+ def self.included(base)
8
+ base.extend(ClassMethods)
9
+ end
10
+
11
+ # Performs the necessary generator for a given component choice
12
+ # execute_component_setup(:mock, 'rr')
13
+ def execute_component_setup(component, choice)
14
+ return true && say("Skipping generator for #{component} component...", :yellow) if choice.to_s == 'none'
15
+ say "Applying '#{choice}' (#{component})...", :yellow
16
+ apply_component_for(choice, component)
17
+ send("setup_#{component}") if respond_to?("setup_#{component}")
18
+ end
19
+
20
+ # Returns the related module for a given component and option
21
+ # generator_module_for('rr', :mock)
22
+ def apply_component_for(choice, component)
23
+ # I need to override Thor#apply because for unknow reason :verobse => false break tasks.
24
+ path = File.expand_path(File.dirname(__FILE__) + "/components/#{component.to_s.pluralize}/#{choice}.rb")
25
+ say_status :apply, "#{component.to_s.pluralize}/#{choice}"
26
+ shell.padding += 1
27
+ instance_eval(open(path).read)
28
+ shell.padding -= 1
29
+ end
30
+
31
+ # Returns the component choice stored within the .component file of an application
32
+ # fetch_component_choice(:mock)
33
+ def fetch_component_choice(component)
34
+ retrieve_component_config(destination_root('.components'))[component]
35
+ end
36
+
37
+ # Set the component choice and store it in the .component file of the application
38
+ # store_component_choice(:renderer, :haml)
39
+ def store_component_choice(key, value)
40
+ path = destination_root('.components')
41
+ config = retrieve_component_config(path)
42
+ config[key] = value
43
+ create_file(path, :force => true) { config.to_yaml }
44
+ value
45
+ end
46
+
47
+ # Loads the component config back into a hash
48
+ # i.e retrieve_component_config(...) => { :mock => 'rr', :test => 'riot', ... }
49
+ def retrieve_component_config(target)
50
+ YAML.load_file(target)
51
+ end
52
+
53
+ # Prompts the user if necessary until a valid choice is returned for the component
54
+ # resolve_valid_choice(:mock) => 'rr'
55
+ def resolve_valid_choice(component)
56
+ available_string = self.class.available_choices_for(component).join(", ")
57
+ choice = options[component]
58
+ until valid_choice?(component, choice)
59
+ say("Option for --#{component} '#{choice}' is not available.", :red)
60
+ choice = ask("Please enter a valid option for #{component} (#{available_string}):")
61
+ end
62
+ choice
63
+ end
64
+
65
+ # Returns true if the option passed is a valid choice for component
66
+ # valid_option?(:mock, 'rr')
67
+ def valid_choice?(component, choice)
68
+ choice.present? && self.class.available_choices_for(component).include?(choice.to_sym)
69
+ end
70
+
71
+ # Creates a component_config file at the destination containing all component options
72
+ # Content is a yamlized version of a hash containing component name mapping to chosen value
73
+ def store_component_config(destination)
74
+ components = @_components || options
75
+ create_file(destination) do
76
+ self.class.component_types.inject({}) { |result, comp|
77
+ result[comp] = components[comp].to_s; result
78
+ }.to_yaml
79
+ end
80
+ end
81
+
82
+ # Returns the root for this thor class (also aliased as destination root).
83
+ def destination_root(*paths)
84
+ File.expand_path(File.join(@destination_stack.last, paths))
85
+ end
86
+
87
+ # Returns true if inside a Appjam application
88
+ def in_app_root?
89
+ File.exist?(destination_root('Classes'))
90
+ end
91
+
92
+ # Returns the field with an unacceptable name(for symbol) else returns nil
93
+ def invalid_fields(fields)
94
+ results = fields.select { |field| field.split(":").first =~ /\W/ }
95
+ results.empty? ? nil : results
96
+ end
97
+
98
+ # Returns the app_name for the application at root
99
+ def fetch_app_name(app='app')
100
+ app_path = destination_root(app, 'app.rb')
101
+ @app_name ||= File.read(app_path).scan(/class\s(.*?)\s</).flatten[0]
102
+ end
103
+
104
+ # Ask something to the user and receives a response.
105
+ #
106
+ # ==== Example
107
+ #
108
+ # ask("What is your app name?")
109
+ def ask(statement, default=nil, color=nil)
110
+ default_text = default ? " (leave blank for #{default}):" : nil
111
+ say("#{statement}#{default_text} ", color)
112
+ result = $stdin.gets.strip
113
+ result.blank? ? default : result
114
+ end
115
+
116
+ # Raise SystemExit if the app is inexistent
117
+ def check_app_existence(app)
118
+ unless File.exist?(destination_root(app))
119
+ say
120
+ say "================================================================="
121
+ say "We didn't found #{app.underscore.downcase}! "
122
+ say "================================================================="
123
+ say
124
+ # raise SystemExit
125
+ end
126
+ end
127
+
128
+ # Ensure that project name is valid, else raise an NameError
129
+ def valid_constant?(name)
130
+ if name =~ /^\d/
131
+ raise ::NameError, "Project name #{name} cannot start with numbers"
132
+ elsif name =~ /^\W/
133
+ raise ::NameError, "Project name #{name} cannot start with non-word character"
134
+ end
135
+ end
136
+
137
+ module ClassMethods
138
+ # Defines a class option to allow a component to be chosen and add to component type list
139
+ # Also builds the available_choices hash of which component choices are supported
140
+ # component_option :test, "Testing framework", :aliases => '-t', :choices => [:bacon, :shoulda]
141
+ def component_option(name, caption, options = {})
142
+ (@component_types ||= []) << name # TODO use ordered hash and combine with choices below
143
+ (@available_choices ||= Hash.new)[name] = options[:choices]
144
+ description = "The #{caption} component (#{options[:choices].join(', ')}, none)"
145
+ class_option name, :default => options[:default] || options[:choices].first, :aliases => options[:aliases], :desc => description
146
+ end
147
+
148
+ # Tell to Appjam that for this Thor::Group is necessary a task to run
149
+ def require_arguments!
150
+ @require_arguments = true
151
+ end
152
+
153
+ # Return true if we need an arguments for our Thor::Group
154
+ def require_arguments?
155
+ @require_arguments
156
+ end
157
+
158
+ # Returns the compiled list of component types which can be specified
159
+ def component_types
160
+ @component_types
161
+ end
162
+
163
+ # Returns the list of available choices for the given component (including none)
164
+ def available_choices_for(component)
165
+ @available_choices[component] + [:none]
166
+ end
167
+ end
168
+ end # Actions
169
+ end # Generators
170
+ end # Appjam
@@ -0,0 +1,42 @@
1
+ require 'thor/group'
2
+
3
+ module Appjam
4
+ module Generators
5
+ ##
6
+ # This class bootstrap +config/boot+ and perform +Appjam::Generators.load_components!+ for handle
7
+ # 3rd party generators
8
+ #
9
+ class Cli < Thor::Group
10
+
11
+ # Include related modules
12
+ include Thor::Actions
13
+
14
+ class_option :root, :desc => "The root destination", :aliases => '-r', :default => ".", :type => :string
15
+
16
+ # We need to TRY to load boot because some of our app dependencies maybe have
17
+ # custom generators, so is necessary know who are.
18
+ def load_boot
19
+ begin
20
+ ENV['BUNDLE_GEMFILE'] = File.join(options[:root], "Gemfile") if options[:root]
21
+ rescue Exception => e
22
+ puts "=> Problem loading #{boot}"
23
+ puts ["=> #{e.message}", *e.backtrace].join("\n ")
24
+ end
25
+ end
26
+
27
+ def setup
28
+ Appjam::Generators.load_components!
29
+
30
+ generator_kind = ARGV.delete_at(0).to_s.downcase.to_sym if ARGV[0].present?
31
+ generator_class = Appjam::Generators.mappings[generator_kind]
32
+
33
+ if generator_class
34
+ args = ARGV.empty? && generator_class.require_arguments? ? ["-h"] : ARGV
35
+ generator_class.start(args)
36
+ else
37
+ puts "Please specify generator to use (#{Appjam::Generators.mappings.keys.join(", ")})"
38
+ end
39
+ end
40
+ end # Cli
41
+ end # Generators
42
+ end # Appjam
@@ -0,0 +1,51 @@
1
+ require 'thor'
2
+ require 'thor/group'
3
+ require 'thor/actions'
4
+ require 'active_support/core_ext/string'
5
+
6
+ module Appjam
7
+ module Generators
8
+ class Model < Thor::Group
9
+
10
+ # Add this generator to our appjam
11
+ Appjam::Generators.add_generator(:model, self)
12
+
13
+ # Define the source template root
14
+ def self.source_root; File.expand_path(File.dirname(__FILE__)); end
15
+ def self.banner; "appjam model [name]"; end
16
+
17
+ # Include related modules
18
+ include Thor::Actions
19
+
20
+ desc "Description:\n\n\tappjam will generates an new PureMvc Model for iphone"
21
+
22
+ argument :name, :desc => "The name of your puremvc model"
23
+
24
+ class_option :root, :desc => "The root destination", :aliases => '-r', :default => ".", :type => :string
25
+ class_option :destroy, :aliases => '-d', :default => false, :type => :boolean
26
+
27
+ # Show help if no argv given
28
+ #require_arguments!
29
+
30
+ def in_app_root?
31
+ File.exist?('Classes')
32
+ end
33
+
34
+ def create_app
35
+ self.destination_root = options[:root]
36
+ @project_name = name.gsub(/\W/, "_").downcase
37
+ @class_name = name.gsub(/\W/, "_").capitalize
38
+ app = options[:model]
39
+ self.behavior = :revoke if options[:destroy]
40
+
41
+ say (<<-TEXT).gsub(/ {10}/,'')
42
+
43
+ =================================================================
44
+ Your #{@class_name} Model app has been generated.
45
+ =================================================================
46
+
47
+ TEXT
48
+ end
49
+ end # Model
50
+ end # Generators
51
+ end # Appjam
@@ -2,13 +2,14 @@ require 'thor'
2
2
  require 'thor/group'
3
3
  require 'thor/actions'
4
4
  require 'active_support/core_ext/string'
5
+ require File.dirname(__FILE__) + '/actions'
5
6
 
6
7
  module Appjam
7
8
  module Generators
8
9
  class Project < Thor::Group
9
10
 
10
11
  # Add this generator to our appjam
11
- Appjam::Generators.add_generator(:app, self)
12
+ Appjam::Generators.add_generator(:project, self)
12
13
 
13
14
  # Define the source template root
14
15
  def self.source_root; File.expand_path(File.dirname(__FILE__)); end
@@ -16,6 +17,7 @@ module Appjam
16
17
 
17
18
  # Include related modules
18
19
  include Thor::Actions
20
+ include Appjam::Generators::Actions
19
21
 
20
22
  desc "Description:\n\n\tappjam will generates an new PureMvc application for iphone"
21
23
 
@@ -32,10 +34,11 @@ module Appjam
32
34
  end
33
35
 
34
36
  def create_app
35
- self.destination_root = options[:root]
36
- @project_name = name.gsub(/\W/, "_").downcase
37
+ valid_constant?(options[:project] || name)
38
+ @project_name = (options[:app] || name).gsub(/\W/, "_").downcase
37
39
  @class_name = name.gsub(/\W/, "_").capitalize
38
- app = options[:app]
40
+ self.destination_root = options[:root]
41
+ project = options[:project]
39
42
  self.behavior = :revoke if options[:destroy]
40
43
 
41
44
  empty_directory "#{@project_name}"
@@ -63,6 +66,6 @@ module Appjam
63
66
 
64
67
  TEXT
65
68
  end
66
- end # App
69
+ end # Project
67
70
  end # Generators
68
- end # IphoneMvc
71
+ end # Appjam