puer 0.0.1 → 0.0.2

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