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 +1 -1
- data/bin/puer +2 -54
- data/lib/puer.rb +64 -0
- data/lib/puer/command.rb +27 -0
- data/lib/puer/config.rb +12 -7
- data/lib/puer/generators/actions.rb +183 -0
- data/lib/puer/generators/cli.rb +70 -0
- data/lib/puer/generators/controller.rb +66 -0
- data/lib/puer/generators/gist.rb +247 -0
- data/lib/puer/generators/gist.yml +43 -0
- data/lib/puer/generators/help.rb +82 -0
- data/lib/puer/generators/jam.rb +80 -0
- data/lib/puer/generators/model.rb +65 -0
- data/lib/puer/generators/search.rb +94 -0
- data/lib/puer/generators/templates/controller.tt +9 -0
- data/lib/puer/generators/templates/model.tt +13 -0
- data/lib/puer/generators/templates/view.tt +12 -0
- data/lib/puer/generators/xib.rb +69 -0
- data/lib/puer/session.rb +28 -17
- data/lib/puer/tasks.rb +22 -0
- data/lib/puer/tasks/plugin.rb +73 -0
- data/lib/puer/utility.rb +30 -0
- data/lib/puer/version.rb +9 -0
- data/lib/puer/view.rb +48 -0
- metadata +22 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
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
|
-
|
27
|
-
@show_warnings = w
|
28
|
-
end
|
19
|
+
require File.expand_path(File.dirname(__FILE__) + '/../lib/puer/generators/cli')
|
29
20
|
|
30
|
-
|
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
|
data/lib/puer.rb
CHANGED
@@ -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
|
+
|
data/lib/puer/command.rb
ADDED
@@ -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
|
data/lib/puer/config.rb
CHANGED
@@ -1,10 +1,15 @@
|
|
1
|
-
|
2
|
-
|
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
|