appjam 0.1.0.pre6 → 0.1.0.pre9

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 (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