puer 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.0.2
data/bin/puer CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
+ require 'rubygems'
4
5
  require 'rubygems' unless defined?(Gem)
5
6
  require 'thread'
6
7
 
@@ -14,3 +15,60 @@ unless $LOAD_PATH.include?(lib_dir)
14
15
  end
15
16
 
16
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
+
26
+ opts.on("-w", "--[no-]warnings", "Show warnings") do |w|
27
+ @show_warnings = w
28
+ end
29
+
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!
39
+
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
@@ -1 +1,6 @@
1
- puts "Have a cup of puer"
1
+ lib_dir = File.expand_path(File.join(File.dirname(__FILE__),'puer'))
2
+ unless $LOAD_PATH.include?(lib_dir)
3
+ $LOAD_PATH << lib_dir
4
+ end
5
+
6
+ require 'xibtoti'
@@ -0,0 +1,24 @@
1
+ ignore_properties 'contentStretch', 'simulatedStatusBarMetrics', 'simulatedOrientationMetrics'
2
+ ignore_classes 'IBProxyObject'
3
+
4
+ # To get another creation call than standard
5
+ # Ti.UI.create#{name}
6
+ # give a array as value: 'IBUIWindow' => ['Window', 'myWindowCall']
7
+ classes 'IBUIWindow' => 'Window',
8
+ 'IBUIView' => 'View',
9
+ 'IBUILabel' => 'Label',
10
+ 'IBUIButton' => 'Button'
11
+
12
+ # Available types:
13
+ # val(:output)
14
+ # bool(:output) # Where '0' gives {:output => false} and '1' gives {:output => true}
15
+ # lookup(:output, {'yes' => true, 'no' => false})
16
+ # color(:output)
17
+ # font(:output)
18
+ # vextor(:x, :y) # Where '{1, 2}' => {:x => 1, :y => 2}
19
+ properties 'backgroundColor' => color(:backgroundColor),
20
+ 'font' => font(:font),
21
+ 'frameOrigin' => vector(:top, :bottom),
22
+ 'frameSize' => vector(:height, :width),
23
+ 'text' => val(:text),
24
+ 'textColor' => color(:color)
@@ -0,0 +1,36 @@
1
+ # Converters converts data in the xib files property bag to the NodeInfos property bag.
2
+ # The output key it will have is stored here. The converter can be created with a conversion block
3
+ # Converter.new :output {|v| Convert value v here...}
4
+
5
+ class Converter
6
+ def initialize(output, &conversion)
7
+ @output = output
8
+ @conversion = conversion || proc {|v| v}
9
+ end
10
+
11
+ def props_for(value)
12
+ converted_value = @conversion.call(value)
13
+ if converted_value
14
+ { @output => converted_value }
15
+ end
16
+ end
17
+ end
18
+
19
+ # MultiConverter is used for cases when a property in the xhib file's property bag needs multiple
20
+ # properties in JS
21
+ # Example: {'frameOrigin' => "{123, 456}"} should give {:top => 123, :bottom => 456}
22
+ # Done by: MultiConverter.new([:top, :bottom], /\{(\d+), (\d+)\}/) {|v| v.to_i}
23
+
24
+ class MultiConverter < Converter
25
+ def initialize(outputs, regex, &conversion)
26
+ @outputs = outputs
27
+ @regex = regex
28
+ @conversion = conversion || proc {|v| v}
29
+ end
30
+
31
+ def props_for(value)
32
+ if match = @regex.match(value)
33
+ Hash[@outputs.zip(match.captures.map(&@conversion))]
34
+ end
35
+ end
36
+ end
data/lib/puer/nodes.rb ADDED
@@ -0,0 +1,56 @@
1
+ # NodeInfo contains the information from the xib, both hierarchy and properties
2
+
3
+ class NodeInfo
4
+ def initialize(name, node_id, node_class, subviews)
5
+ @name = name
6
+ @node_id = node_id
7
+ @node_class = node_class
8
+ @subviews = subviews
9
+ @properties = {}
10
+ end
11
+
12
+ attr_reader :properties, :name, :node_class, :subviews
13
+
14
+ def self.enumerate(name)
15
+ "#{name}#{(@@name_counters ||= Hash.new {0})[name]+=1}"
16
+ end
17
+
18
+ def self.for(hierarchy, data, session)
19
+ id = hierarchy['object-id'].to_s
20
+ info = data[id]
21
+ node_class = session.class_info_for info['class']
22
+ if node_class
23
+ name = hierarchy['name'] || enumerate(node_class.name.downcase)
24
+ subviews = (hierarchy['children'] || []).map {|child_hierarchy| NodeInfo.for(child_hierarchy, data, session)}.compact
25
+ node = NodeInfo.new name, id, node_class, subviews
26
+ info.each do |prop, value|
27
+ if converter = session.converter_for(prop)
28
+ props = converter.props_for(value)
29
+ if props
30
+ node.properties.merge! props
31
+ else
32
+ session.log(:error, "Could not convert #{prop}: #{value}")
33
+ end
34
+ else
35
+ session.log(:warning, "Skipped property for #{info['class']}: #{prop}") unless session.ignore_property? prop
36
+ end
37
+ end
38
+ node
39
+ else
40
+ session.log(:warning, "Skipped class #{info['class']}") unless session.ignore_class? info['class']
41
+ end
42
+ node
43
+ end
44
+ end
45
+
46
+ # ClassInfo contains all known information on the class of the node info (Windows, Views... etc)
47
+
48
+ class ClassInfo
49
+ def initialize(name, creation_call="Ti.UI.create#{name}")
50
+ @name = name
51
+ @creation_call = creation_call
52
+ end
53
+
54
+ attr_reader :name, :creation_call
55
+ end
56
+
@@ -0,0 +1,129 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ require 'nodes'
3
+ require 'converters'
4
+ require 'rubygems'
5
+ require 'plist'
6
+
7
+ # Stores all configurable info on how to translate the xib to JS
8
+ # The session is created from a config file.
9
+
10
+ class Session
11
+ def initialize(path)
12
+ @ignore_properties = []
13
+ @ignore_classes = []
14
+ @classes = {}
15
+ @properties = {}
16
+ @log = []
17
+ File.open path do |file|
18
+ eval file.read
19
+ end
20
+ end
21
+
22
+ attr_reader :out
23
+
24
+ def parse_file(file)
25
+ data = Plist::parse_xml( %x[ibtool #{file} --hierarchy --objects --connections] )
26
+ @out = data['com.apple.ibtool.document.hierarchy'].map {|hierarchy| NodeInfo.for hierarchy, data['com.apple.ibtool.document.objects'], self}.compact
27
+ data['com.apple.ibtool.document.connections'].each do |connection|
28
+ # TODO
29
+ end
30
+ @out
31
+ end
32
+
33
+ def full_log(severities=[])
34
+ excluded = @log.map(&:first).uniq - severities
35
+ (excluded.empty? ? '' : "There were log entries of severity: #{excluded.join ', '}\n") +
36
+ @log.map do |severity, message|
37
+ "[#{severity}] #{message}" if severities.include? severity
38
+ end.compact.join("\n")
39
+ end
40
+
41
+ def has_errors?
42
+ @log.any? {|severity, message| severity == :error}
43
+ end
44
+
45
+ def log(severity, message)
46
+ @log.push [severity, message]
47
+ end
48
+
49
+ def ignore_class?(class_name)
50
+ @ignore_classes.include? class_name
51
+ end
52
+
53
+ def ignore_property?(property_name)
54
+ @ignore_properties.include? property_name
55
+ end
56
+
57
+ def converter_for(property_name)
58
+ @properties[property_name]
59
+ end
60
+
61
+ def class_info_for(class_name)
62
+ @classes[class_name]
63
+ end
64
+
65
+ def classes(class_hash)
66
+ class_hash.each do |key, value|
67
+ @classes[key] = ClassInfo.new(*value)
68
+ end
69
+ end
70
+
71
+ def ignore_properties(*names)
72
+ @ignore_properties += names
73
+ end
74
+
75
+ def ignore_classes(*names)
76
+ @ignore_classes += names
77
+ end
78
+
79
+ def properties(properties_hash)
80
+ @properties.merge! properties_hash
81
+ end
82
+
83
+ # Color helper methods
84
+
85
+ def hex(v)
86
+ "%02x" % (v.to_f*255).round
87
+ end
88
+
89
+ def rgba(r, g, b, a)
90
+ "##{hex(r)}#{hex(g)}#{hex(b)}#{hex(a)}"
91
+ end
92
+
93
+ # Methods for converter creation in config file
94
+
95
+ def val(name)
96
+ Converter.new(name)
97
+ end
98
+
99
+ def bool(name)
100
+ Converter.new(name) {|v| v==1}
101
+ end
102
+
103
+ def lookup(name, hash)
104
+ Converter.new(name) {|v| hash[v]}
105
+ end
106
+
107
+ def color(name)
108
+ Converter.new(name) do |v|
109
+ case v
110
+ when /NS(?:Calibrated|Device)RGBColorSpace (\d+(?:\.\d+)?) (\d+(?:\.\d+)?) (\d+(?:\.\d+)?) (\d+(?:\.\d+)?)/
111
+ rgba($1, $2, $3, $4)
112
+ when /NS(?:Calibrated|Device)WhiteColorSpace (\d+(?:\.\d+)?) (\d+(?:\.\d+)?)/
113
+ rgba($1, $1, $1, $2)
114
+ when /NSCustomColorSpace Generic Gray colorspace (\d+(?:\.\d+)?) (\d+(?:\.\d+)?)/
115
+ rgba($1, $1, $1, $2)
116
+ end
117
+ end
118
+ end
119
+
120
+ def font(name)
121
+ Converter.new(name) do |v|
122
+ {:fontFamily => v['Family'], :fontSize => v['Size']}
123
+ end
124
+ end
125
+
126
+ def vector(x, y)
127
+ MultiConverter.new([x, y], /\{(\d+), (\d+)\}/) {|v| v.to_i}
128
+ end
129
+ end
@@ -0,0 +1,33 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ require 'session'
3
+
4
+ def inline_js_for(data)
5
+
6
+ case data
7
+ when Hash
8
+ '{' + data.map {|k,v| "#{k}:#{inline_js_for(v)}"}.join(',') + '}'
9
+ when String
10
+ "'#{data}'"
11
+ else
12
+ data.to_s
13
+ end
14
+
15
+ end
16
+
17
+ def creation_call(name, class_name, info)
18
+ "#{name} = #{class_name}({\n" +
19
+ info.keys.sort.map {|key| "\t#{key}:#{inline_js_for(info[key])}"}.join(",\n") + "\n});"
20
+ end
21
+
22
+ def js_sections_for(node)
23
+ [creation_call(node.name, node.node_class.creation_call, node.properties)] +
24
+ node.subviews.map {|child| [js_sections_for(child), "#{node.name}.add(#{child.name});"]}.flatten
25
+ end
26
+
27
+ def js_for(nodes)
28
+ nodes.map {|node| js_sections_for(node)}.flatten.join("\n\n")
29
+ end
30
+
31
+ def js_comments_for text
32
+ "" #text.map {|line| line.chomp.empty? ? line : "// #{line}"}.join + "\n"
33
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-23 00:00:00.000000000 Z
12
+ date: 2012-10-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thor
@@ -75,6 +75,22 @@ dependencies:
75
75
  - - ! '>='
76
76
  - !ruby/object:Gem::Version
77
77
  version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: plist
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
78
94
  - !ruby/object:Gem::Dependency
79
95
  name: rdoc
80
96
  requirement: !ruby/object:Gem::Requirement
@@ -220,45 +236,29 @@ dependencies:
220
236
  - !ruby/object:Gem::Version
221
237
  version: 2.3.1
222
238
  - !ruby/object:Gem::Dependency
223
- name: ruby-prof
224
- requirement: !ruby/object:Gem::Requirement
225
- none: false
226
- requirements:
227
- - - ! '>='
228
- - !ruby/object:Gem::Version
229
- version: 0.9.1
230
- type: :development
231
- prerelease: false
232
- version_requirements: !ruby/object:Gem::Requirement
233
- none: false
234
- requirements:
235
- - - ! '>='
236
- - !ruby/object:Gem::Version
237
- version: 0.9.1
238
- - !ruby/object:Gem::Dependency
239
- name: system_timer
239
+ name: activesupport
240
240
  requirement: !ruby/object:Gem::Requirement
241
241
  none: false
242
242
  requirements:
243
243
  - - ! '>='
244
244
  - !ruby/object:Gem::Version
245
- version: '1.0'
246
- type: :development
245
+ version: 3.2.8
246
+ type: :runtime
247
247
  prerelease: false
248
248
  version_requirements: !ruby/object:Gem::Requirement
249
249
  none: false
250
250
  requirements:
251
251
  - - ! '>='
252
252
  - !ruby/object:Gem::Version
253
- version: '1.0'
253
+ version: 3.2.8
254
254
  - !ruby/object:Gem::Dependency
255
- name: activesupport
255
+ name: grit
256
256
  requirement: !ruby/object:Gem::Requirement
257
257
  none: false
258
258
  requirements:
259
259
  - - ! '>='
260
260
  - !ruby/object:Gem::Version
261
- version: 3.2.8
261
+ version: '0'
262
262
  type: :runtime
263
263
  prerelease: false
264
264
  version_requirements: !ruby/object:Gem::Requirement
@@ -266,9 +266,9 @@ dependencies:
266
266
  requirements:
267
267
  - - ! '>='
268
268
  - !ruby/object:Gem::Version
269
- version: 3.2.8
269
+ version: '0'
270
270
  - !ruby/object:Gem::Dependency
271
- name: grit
271
+ name: i18n
272
272
  requirement: !ruby/object:Gem::Requirement
273
273
  none: false
274
274
  requirements:
@@ -284,7 +284,7 @@ dependencies:
284
284
  - !ruby/object:Gem::Version
285
285
  version: '0'
286
286
  - !ruby/object:Gem::Dependency
287
- name: i18n
287
+ name: hirb
288
288
  requirement: !ruby/object:Gem::Requirement
289
289
  none: false
290
290
  requirements:
@@ -300,7 +300,7 @@ dependencies:
300
300
  - !ruby/object:Gem::Version
301
301
  version: '0'
302
302
  - !ruby/object:Gem::Dependency
303
- name: hirb
303
+ name: cli-colorize
304
304
  requirement: !ruby/object:Gem::Requirement
305
305
  none: false
306
306
  requirements:
@@ -316,7 +316,7 @@ dependencies:
316
316
  - !ruby/object:Gem::Version
317
317
  version: '0'
318
318
  - !ruby/object:Gem::Dependency
319
- name: cli-colorize
319
+ name: rdoc
320
320
  requirement: !ruby/object:Gem::Requirement
321
321
  none: false
322
322
  requirements:
@@ -332,7 +332,7 @@ dependencies:
332
332
  - !ruby/object:Gem::Version
333
333
  version: '0'
334
334
  - !ruby/object:Gem::Dependency
335
- name: rdoc
335
+ name: yajl-ruby
336
336
  requirement: !ruby/object:Gem::Requirement
337
337
  none: false
338
338
  requirements:
@@ -348,7 +348,7 @@ dependencies:
348
348
  - !ruby/object:Gem::Version
349
349
  version: '0'
350
350
  - !ruby/object:Gem::Dependency
351
- name: yajl-ruby
351
+ name: plist
352
352
  requirement: !ruby/object:Gem::Requirement
353
353
  none: false
354
354
  requirements:
@@ -377,6 +377,11 @@ files:
377
377
  - README.md
378
378
  - VERSION
379
379
  - lib/puer.rb
380
+ - lib/puer/config.rb
381
+ - lib/puer/converters.rb
382
+ - lib/puer/nodes.rb
383
+ - lib/puer/session.rb
384
+ - lib/puer/xibtoti.rb
380
385
  - !binary |-
381
386
  YmluL3B1ZXI=
382
387
  homepage: http://github.com/eiffelqiu/puer
@@ -394,7 +399,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
394
399
  version: '0'
395
400
  segments:
396
401
  - 0
397
- hash: 3248177067678294062
402
+ hash: -841221982100314824
398
403
  required_rubygems_version: !ruby/object:Gem::Requirement
399
404
  none: false
400
405
  requirements:
@@ -403,7 +408,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
403
408
  version: '0'
404
409
  requirements: []
405
410
  rubyforge_project:
406
- rubygems_version: 1.8.21
411
+ rubygems_version: 1.8.24
407
412
  signing_key:
408
413
  specification_version: 3
409
414
  summary: Titanium Starter Project Generate Tools