puer 0.0.4 → 0.0.6

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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.4
1
+ 0.0.6
data/bin/puer CHANGED
@@ -15,60 +15,8 @@ unless $LOAD_PATH.include?(lib_dir)
15
15
  end
16
16
 
17
17
  require 'puer'
18
- require 'optparse'
19
-
20
- OptionParser.new do |opts|
21
- opts.banner =<<END
22
- Usage: puer [options] [filename]
23
- Usage: puer all # convert all xib files to js under current directory
24
- END
25
18
 
26
- opts.on("-w", "--[no-]warnings", "Show warnings") do |w|
27
- @show_warnings = w
28
- end
19
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/puer/generators/cli')
29
20
 
30
- opts.on("-o", "--output-file name", "Specify output file") do |o|
31
- @output_file = o
32
- end
33
-
34
- opts.on("-c", "--config-file name", "Specify config file") do |o|
35
- @config_file = o
36
- end
37
-
38
- end.parse!
21
+ Puer::Generators::Cli.start(ARGV)
39
22
 
40
- if ARGV.size == 1
41
-
42
- case ARGV[0]
43
- when "all"
44
- Dir.glob(File.join('**','*.xib')).each do |s|
45
- puts "#{s} is converted to #{File.basename(s, '.*')}.js "
46
- system "puer #{s} -o #{File.basename(s, '.*')}.js"
47
- exit
48
- end
49
- else
50
- input_file = ARGV.first
51
-
52
- session = Session.new @config_file || File.join("#{File.dirname(__FILE__)}/../lib/puer", 'config.rb')
53
- session.parse_file input_file
54
- if session.has_errors?
55
- puts "Aborted!"
56
- puts session.full_log [:error]
57
- else
58
- severities = []
59
- severities.unshift :warning if @show_warnings
60
- log = session.full_log severities
61
- script = js_comments_for(log) + js_for(session.out)
62
- if @output_file
63
- File.open(@output_file, 'w') do |file|
64
- file.write script
65
- end
66
- puts log
67
- else
68
- puts script
69
- end
70
- end
71
- end
72
- else
73
- puts "For help, type: puer -h"
74
- end
@@ -4,3 +4,67 @@ unless $LOAD_PATH.include?(lib_dir)
4
4
  end
5
5
 
6
6
  require 'xibtoti'
7
+
8
+ require 'thread'
9
+ require 'puer/version'
10
+ require 'puer/tasks'
11
+ require 'active_support'
12
+
13
+ module Puer
14
+ ##
15
+ # This method return the correct location of mvc-gen bin or
16
+ # exec it using Kernel#system with the given args
17
+ #
18
+ def self.bin_gen(*args)
19
+ @_mvc_gen_bin ||= [IphoneMvc.ruby_command, File.expand_path("../bin/puer", __FILE__)]
20
+ args.empty? ? @_mvc_gen_bin : system(args.unshift(@_mvc_gen_bin).join(" "))
21
+ end
22
+
23
+ ##
24
+ # This module it's used for register generators
25
+ #
26
+ module Generators
27
+
28
+ DEV_PATH = File.expand_path("../../", File.dirname(__FILE__))
29
+
30
+ class << self
31
+
32
+ ##
33
+ # Here we store our generators paths
34
+ #
35
+ def load_paths
36
+ @_files ||= []
37
+ end
38
+
39
+ ##
40
+ # Return a ordered list of task with their class
41
+ #
42
+ def mappings
43
+ @_mappings ||= ActiveSupport::OrderedHash.new
44
+ end
45
+
46
+ ##
47
+ # Gloabl add a new generator class
48
+ #
49
+ def add_generator(name, klass)
50
+ mappings[name] = klass
51
+ end
52
+
53
+ ##
54
+ # Load Global Actions and Component Actions then all files in +load_path+.
55
+ #
56
+ def load_components!
57
+ require 'puer/generators/actions'
58
+ load_paths.flatten.each { |file| require file }
59
+ end
60
+ end
61
+ end # Generators
62
+ end # Puer
63
+
64
+ ##
65
+ # We add our generators to Puer::Genererator
66
+ #
67
+ Puer::Generators.load_paths << Dir[File.dirname(__FILE__) + '/puer/generators/{controller,model,xib,lib,gist,search,help}.rb']
68
+
69
+
70
+
@@ -0,0 +1,27 @@
1
+ require 'rbconfig'
2
+
3
+ module Puer
4
+ ##
5
+ # This method return the correct location of puer bin or
6
+ # exec it using Kernel#system with the given args
7
+ #
8
+ def self.bin(*args)
9
+ @_puer_bin ||= [self.ruby_command, File.expand_path("../../../bin/puer", __FILE__)]
10
+ args.empty? ? @_puer_bin : system(args.unshift(@_puer_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 # Puer
@@ -1,10 +1,15 @@
1
- ignore_properties 'contentStretch', 'simulatedStatusBarMetrics', 'simulatedOrientationMetrics'
2
- ignore_classes 'IBProxyObject'
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ require 'session'
3
+
4
+ $config = Session.new
5
+
6
+ $config.ignore_properties 'contentStretch', 'simulatedStatusBarMetrics', 'simulatedOrientationMetrics'
7
+ $config.ignore_classes 'IBProxyObject'
3
8
 
4
9
  # To get another creation call than standard
5
10
  # Ti.UI.create#{name}
6
11
  # give a array as value: 'IBUIWindow' => ['Window', 'myWindowCall']
7
- classes 'IBUIWindow' => 'Window',
12
+ $config.classes 'IBUIWindow' => 'Window',
8
13
  'IBUIView' => 'View',
9
14
  'IBUILabel' => 'Label',
10
15
  'IBUIButton' => 'Button',
@@ -23,8 +28,8 @@ classes 'IBUIWindow' => 'Window',
23
28
  # font(:output)
24
29
  # vextor(:x, :y) # Where '{1, 2}' => {:x => 1, :y => 2}
25
30
  # properties 'backgroundColor' => color(:backgroundColor),
26
- properties 'font' => font(:font),
27
- 'frameOrigin' => vector(:top, :bottom),
28
- 'frameSize' => vector(:height, :width),
29
- 'text' => val(:text)
31
+ $config.properties 'font' => $config.font(:font),
32
+ 'frameOrigin' => $config.vector(:top, :bottom),
33
+ 'frameSize' => $config.vector(:height, :width),
34
+ 'text' => $config.val(:text)
30
35
  #'textColor' => color(:color)
@@ -0,0 +1,183 @@
1
+ module Puer
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 Puer application
88
+ def in_app_root?
89
+ #File.exist?(destination_root('Classes'))
90
+ Dir.glob("tiapp.xml").count >= 1
91
+ end
92
+
93
+ # Returns the field with an unacceptable name(for symbol) else returns nil
94
+ def invalid_fields(fields)
95
+ results = fields.select { |field| field.split(":").first =~ /\W/ }
96
+ results.empty? ? nil : results
97
+ end
98
+
99
+ # Returns the app_name for the application at root
100
+ def fetch_app_name(app='app')
101
+ app_path = destination_root(app, 'app.rb')
102
+ @app_name ||= File.read(app_path).scan(/class\s(.*?)\s</).flatten[0]
103
+ end
104
+
105
+ # Ask something to the user and receives a response.
106
+ #
107
+ # ==== Example
108
+ #
109
+ # ask("What is your app name?")
110
+ def ask(statement, default=nil, color=nil)
111
+ default_text = default ? " (leave blank for #{default}):" : nil
112
+ say("#{statement}#{default_text} ", color)
113
+ result = $stdin.gets.strip
114
+ result.blank? ? default : result
115
+ end
116
+
117
+ # Raise SystemExit if the app is iexistent
118
+ def check_app_existence(app)
119
+ unless File.exist?(destination_root(app))
120
+ say
121
+ say "================================================================="
122
+ say "We didn't found #{app.underscore.camelize}! "
123
+ say "================================================================="
124
+ say
125
+ # raise SystemExit
126
+ end
127
+ end
128
+
129
+ # Ensure that project name is valid, else raise an NameError
130
+ def valid_constant?(name)
131
+ if name =~ /^\d/
132
+ raise ::NameError, "Project name #{name} cannot start with numbers"
133
+ elsif name =~ /^\W/
134
+ raise ::NameError, "Project name #{name} cannot start with non-word character"
135
+ end
136
+ end
137
+
138
+ ## Detect command and dump it's path
139
+ def which cmd
140
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
141
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
142
+ exts.each { |ext|
143
+ exe = "#{path}/#{cmd}#{ext}"
144
+ return exe if File.executable? exe
145
+ }
146
+ end
147
+ return nil
148
+ end
149
+
150
+ module ClassMethods
151
+ # Defines a class option to allow a component to be chosen and add to component type list
152
+ # Also builds the available_choices hash of which component choices are supported
153
+ # component_option :test, "Testing framework", :aliases => '-t', :choices => [:bacon, :shoulda]
154
+ def component_option(name, caption, options = {})
155
+ (@component_types ||= []) << name # TODO use ordered hash and combine with choices below
156
+ (@available_choices ||= Hash.new)[name] = options[:choices]
157
+ description = "The #{caption} component (#{options[:choices].join(', ')}, none)"
158
+ class_option name, :default => options[:default] || options[:choices].first, :aliases => options[:aliases], :desc => description
159
+ end
160
+
161
+ # Tell to Puer that for this Thor::Group is necessary a task to run
162
+ def require_arguments!
163
+ @require_arguments = true
164
+ end
165
+
166
+ # Return true if we need an arguments for our Thor::Group
167
+ def require_arguments?
168
+ @require_arguments
169
+ end
170
+
171
+ # Returns the compiled list of component types which can be specified
172
+ def component_types
173
+ @component_types
174
+ end
175
+
176
+ # Returns the list of available choices for the given component (including none)
177
+ def available_choices_for(component)
178
+ @available_choices[component] + [:none]
179
+ end
180
+ end
181
+ end # Actions
182
+ end # Generators
183
+ end # Puer
@@ -0,0 +1,70 @@
1
+ require 'rubygems'
2
+ require 'thor/group'
3
+ require 'cli-colorize'
4
+ require 'hirb'
5
+ require File.dirname(__FILE__) + '/../view'
6
+
7
+ module Puer
8
+ module Generators
9
+ ##
10
+ # This class bootstrap +config/boot+ and perform +Puer::Generators.load_components!+ for handle
11
+ # 3rd party generators
12
+ #
13
+ class Cli < Thor::Group
14
+ include CLIColorize
15
+
16
+ CLIColorize.default_color = :red
17
+
18
+ RENDER_OPTIONS = { :fields => [:category,:command,:description] }
19
+ # Include related modules
20
+ include Thor::Actions
21
+ desc "Puer Version:\t#{Puer::Version::STRING}"
22
+ class_option :help, :desc => "Help screen", :aliases => '-h', :type => :string
23
+
24
+ # We need to TRY to load boot because some of our app dependencies maybe have
25
+ # custom generators, so is necessary know who are.
26
+ def load_boot
27
+ begin
28
+ ENV['BUNDLE_GEMFILE'] = File.join(options[:root], "Gemfile") if options[:root]
29
+ rescue Exception => e
30
+ puts "=> Problem loading #{boot}"
31
+ puts ["=> #{e.message}", *e.backtrace].join("\n ")
32
+ end
33
+ end
34
+
35
+ def setup
36
+ Puer::Generators.load_components!
37
+
38
+ generator_kind = ARGV.delete_at(0).to_s.downcase.to_sym if ARGV[0].present?
39
+ generator_class = Puer::Generators.mappings[generator_kind]
40
+ if generator_class
41
+ args = ARGV.empty? && generator_class.require_arguments? ? ["-h"] : ARGV
42
+ generator_class.start(args)
43
+ else
44
+ puts colorize( "Puer Version: #{Puer::Version::STRING}", { :foreground => :red, :background => :white, :config => :underline } )
45
+ puts
46
+ require 'yaml'
47
+ gistfile = File.expand_path("~") + '/.puer/gist.yml'
48
+ Gist::update_gist unless File.exist?(gistfile)
49
+ begin
50
+ g = YAML.load_file(gistfile)
51
+ rescue ArgumentError => e
52
+ g = YAML.load_file(File.expand_path(File.dirname(__FILE__) + '/gist.yml'))
53
+ end
54
+ puts "notice: a new version '#{g['info']}' released" if g['info'] and g['info'].strip != "#{Puer::Version::STRING}"
55
+ puts
56
+ puts "Puer is a Titanium Starter Project Generate Tool"
57
+ puts
58
+ puts colorize("For more information")
59
+ puts
60
+ puts "puer help"
61
+ puts
62
+ puts colorize("Update latest repository info")
63
+ puts
64
+ puts "puer gist update"
65
+ puts
66
+ end
67
+ end
68
+ end # Cli
69
+ end # Generators
70
+ end # Puer