skeleton-ui 0.1.9 → 0.1.11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d327f051ce08a8b54de5154544b9204b196f132cd3383c0a40d0a0576294fadd
4
- data.tar.gz: 5af318dbb05d21de9519fc1ca0127a68ed01f299a2a0d499d7acd7f69fb35b89
3
+ metadata.gz: 129ebeb0d1f8014b655ec386cc47546974bceb1b3d7117e51b94ce08235045ff
4
+ data.tar.gz: a3ec2f542d04712de55bd079dfa96770817c96aac239951ea2fe58a55bfe9cc7
5
5
  SHA512:
6
- metadata.gz: 3dc4568e47c23add94d82ea95a2afa6babee5db570222d6bb0471e3e1e0fbac889a740b5a150a239f1ce19ca234f1e75bb96156c2df96a27e027f571bc755cb6
7
- data.tar.gz: f23c839cac2dd2d9d21f54fae4e7c02602cabc34401c793e158bf9a3ac64887a17872916b9c446b244de97c44e1ace2f5cdde41f188ffa100bc5f3323e65f303
6
+ metadata.gz: af6e514ead6d99c5636eaf54bce53d8288279d6f7b0a68674ae613b226b87077631a9bcca36dbfda676a0516782cf338a56b10ccad03364f55d97a2187af6084
7
+ data.tar.gz: d7aa3d27c079ea9e084e16e10ebe8f7abb10c9adc4619649c8bdb32f02e0e55d87aab665bf0aa9c0de98a36023f5a18f4798e06bf58cf94c18d8c86e97d18eb8
data/README.md CHANGED
@@ -92,6 +92,7 @@ Docs:
92
92
  ------
93
93
 
94
94
  - [Setting up Skeleton for working with iOS real devices](https://github.com/forqa/skeleton/blob/master/docs/real-ios-device-config.md)
95
+ - [Setting up RVM for deciding permissions problems](https://github.com/alter-al/skeleton/blob/master/docs/permissions_error.md)
95
96
 
96
97
  ## License
97
98
 
data/bin/skeleton CHANGED
@@ -3,6 +3,7 @@
3
3
  require 'commander/import'
4
4
  require_relative '../lib/skeleton'
5
5
  require_relative '../lib/skeleton/root'
6
+ require_relative '../lib/skeleton/logger'
6
7
 
7
8
  module Skeleton
8
9
  program :version, VERSION
@@ -27,9 +28,8 @@ module Skeleton
27
28
  c.description = 'Clear user cache'
28
29
  c.example 'description', 'skeleton clear'
29
30
  c.action do |_args, _options|
30
- base = Base.new
31
- base.clear
32
- base.log.info("Successfully clear user cache")
31
+ Base.new.clear
32
+ Log.info('Successfully clear user cache')
33
33
  end
34
34
  end
35
35
 
@@ -40,7 +40,7 @@ module Skeleton
40
40
  c.option '-p', '--port PORT', String, 'Set web-server port'
41
41
  c.action do |_args, options|
42
42
  options.default(port: 4567)
43
- system("ruby #{Base::ROOT_DIR}/html/server.rb #{options.port}")
43
+ system("ruby #{Base::ROOT_DIR}/server/server.rb #{options.port}")
44
44
  end
45
45
  end
46
46
  end
data/lib/skeleton.rb CHANGED
@@ -1,12 +1,12 @@
1
1
  require 'erb'
2
2
  require 'fileutils'
3
3
  require 'nokogiri'
4
- require 'logger'
5
4
  require 'colorize'
6
5
  require 'mini_magick'
7
6
  require_relative 'skeleton/languages.rb'
8
7
  require_relative 'skeleton/root.rb'
9
8
  require_relative 'skeleton/version'
9
+ require_relative 'skeleton/logger'
10
10
  require_relative 'skeleton/base'
11
11
  require_relative 'skeleton/ios'
12
12
  require_relative 'skeleton/android'
@@ -17,8 +17,6 @@ module Skeleton
17
17
 
18
18
  def initialize(options)
19
19
  self.platform = options.platform
20
- self.udid = options.udid
21
- self.bundle_id = options.bundle
22
20
  self.browser = options.browser
23
21
  @driver = ios? ? IOS.new(options) : Android.new(options)
24
22
  end
@@ -31,16 +29,6 @@ module Skeleton
31
29
  @platform = platform
32
30
  end
33
31
 
34
- def udid=(udid)
35
- raise 'Not set udid [-u arg]' if udid.nil?
36
- @udid = udid
37
- end
38
-
39
- def bundle_id=(bundle_id)
40
- raise 'Not set bundle_id [-b arg]' if @platform == 'ios' && bundle_id.nil?
41
- @bundle_id = bundle_id
42
- end
43
-
44
32
  def run
45
33
  @driver.clear
46
34
  @driver.precondition
@@ -63,9 +51,9 @@ module Skeleton
63
51
  @elements_tree.gsub!('<', '&lt;')
64
52
  @elements_tree.gsub!('>', '&gt;')
65
53
  end
66
- template = File.read("#{Base::ROOT_DIR}/html/template.html.erb")
54
+ template = File.read("#{Base::ROOT_DIR}/server/template.html.erb")
67
55
  result = ERB.new(template).result(binding)
68
- File.open("#{Base::ROOT_DIR}/html/#{lang}.html", 'w+') { |f| f.write(result) }
56
+ File.open("#{Base::ROOT_DIR}/server/#{lang}.html", 'w+') { |f| f.write(result) }
69
57
  end
70
58
  end
71
59
 
@@ -73,19 +61,20 @@ module Skeleton
73
61
  screenshot = Dir["#{Base::ATTACHMENTS_FOLDER}/*.png"].first
74
62
  image = MiniMagick::Image.new(screenshot)
75
63
  image.rotate(90) if image.width > image.height
76
- rescue MiniMagick::Error => e
77
- @driver.log.error(e)
64
+ rescue MiniMagick::Error => err
65
+ Log.warn(err)
78
66
  ensure
79
- FileUtils.cp_r(screenshot, "#{Base::ROOT_DIR}/html/screenshot.png")
67
+ FileUtils.cp_r(screenshot, "#{Base::ROOT_DIR}/server/screenshot.png")
80
68
  end
81
69
 
82
70
  def open_url
83
- port = File.read("#{Base::ROOT_DIR}/html/port")
71
+ port = File.read("#{Base::ROOT_DIR}/server/port")
84
72
  url = "http://localhost:#{port}/skeleton"
85
73
  `open #{url}` if @browser
86
- @driver.log.info("Look at your pretty page objects: \n#{url} 😍")
87
- rescue Errno::ENOENT => err
88
- @driver.log.error("Something went wrong with skeleton server 💩\n#{err}")
74
+ Log.info("Look at your pretty page objects: \n#{url} 😍")
75
+ rescue Errno::ENOENT
76
+ Log.warn('Something went wrong with skeleton server 💩' \
77
+ "\nTry to rerun it (:")
89
78
  end
90
79
 
91
80
  def ios?
@@ -16,20 +16,24 @@ class Android < Base
16
16
  python: :find_element_by_xpath
17
17
  }.freeze
18
18
 
19
- attr_accessor :platform, :udid
19
+ attr_accessor :udid
20
20
 
21
21
  def initialize(options)
22
- self.platform = options.platform
23
22
  self.udid = options.udid
24
23
  @language = Language.new
25
24
  end
26
25
 
27
26
  def skeletoner
28
- log.info('We starting to skeleton your screen 🚀')
27
+ check_udid
28
+ Log.info('We starting to skeleton your screen 🚀')
29
29
  create_page_objects
30
30
  save_screenshot
31
31
  save(code: page_source)
32
- log.info('We successfully skeletoned your screen 👻')
32
+ Log.info('We successfully skeletoned your screen 👻')
33
+ end
34
+
35
+ def devices
36
+ `adb devices`.scan(/\n(.*)\t/).flatten
33
37
  end
34
38
 
35
39
  private
@@ -55,7 +59,7 @@ class Android < Base
55
59
  end
56
60
  i += 1
57
61
  end
58
- locator = "//#{line[CLASS]}[@#{CONTENT_DESC}='#{line[CONTENT_DESC]}]']"
62
+ locator = "//#{line[CLASS]}[@#{CONTENT_DESC}='#{line[CONTENT_DESC]}']]"
59
63
  code_generation(method_name: method_name,
60
64
  locator_type: XPATH,
61
65
  locator_value: locator)
@@ -74,7 +78,7 @@ class Android < Base
74
78
  end
75
79
  i += 1
76
80
  end
77
- locator = "//#{line[CLASS]}[@#{TEXT}='#{text}]'"
81
+ locator = "//#{line[CLASS]}[@#{TEXT}='#{text}']"
78
82
  code_generation(method_name: method_name,
79
83
  locator_type: XPATH,
80
84
  locator_value: locator)
@@ -91,7 +95,7 @@ class Android < Base
91
95
  end
92
96
 
93
97
  def create_page_objects
94
- log.info('Generation page objects for your awesome language 💪')
98
+ Log.info('Generation page objects for your awesome language 💪')
95
99
  page_source_html = Nokogiri::HTML.parse(page_source)
96
100
  page_source_html.css('node').each { |line| create_locator(line) }
97
101
  end
@@ -117,23 +121,33 @@ class Android < Base
117
121
 
118
122
  def page_source
119
123
  unless @page_source
120
- log.info('Getting screen source tree ⚒')
124
+ Log.info('Getting screen source tree ⚒')
121
125
  dump = `adb -s #{@udid} shell uiautomator dump | egrep -o '/.*?xml'`
122
126
  @page_source = `adb -s #{@udid} shell cat #{dump}`
123
127
  if @page_source.empty?
124
- log.fatal('Something went wrong. Check your device')
125
- Process.exit(1)
128
+ Log.error('Something went wrong. Check your device')
126
129
  end
127
- log.info('Successfully getting Screen Source Tree 🔥')
130
+ Log.info('Successfully getting Screen Source Tree 🔥')
128
131
  end
129
132
  @page_source
130
133
  end
131
134
 
132
135
  def save_screenshot
133
- log.info('Saving screenshot 📷')
134
- file_name = "#{@platform}_#{TIMESTAMP}.png"
136
+ Log.info('Saving screenshot 📷')
137
+ file_name = "android_#{TIMESTAMP}.png"
135
138
  `adb -s #{@udid} shell screencap -p /sdcard/#{file_name}`
136
139
  `adb -s #{@udid} pull /sdcard/#{file_name} #{ATTACHMENTS_FOLDER}/`
137
140
  `adb -s #{@udid} shell rm /sdcard/#{file_name}`
138
141
  end
142
+
143
+ def check_udid
144
+ Log.info('Checking device udid 👨‍💻')
145
+ @udid = devices.first if @udid.nil? && devices.size == 1
146
+ return if devices.include?(@udid)
147
+ if @udid.nil?
148
+ Log.error("Provide device udid [-u]")
149
+ elsif !devices.include?(@udid)
150
+ Log.error("No such devices with udid: #{@udid}")
151
+ end
152
+ end
139
153
  end
data/lib/skeleton/base.rb CHANGED
@@ -4,25 +4,20 @@ class Base
4
4
  TIMESTAMP = (Time.now.to_f * 1000).to_i
5
5
 
6
6
  def precondition
7
- create_logger
8
7
  clear
9
- FileUtils.rm_rf("#{ROOT_DIR}/html/screenshot.png")
8
+ FileUtils.rm_rf("#{ROOT_DIR}/server/screenshot.png")
10
9
  FileUtils.mkdir_p(PAGE_OBJECTS_FOLDER)
11
10
  FileUtils.mkdir_p(ATTACHMENTS_FOLDER)
12
11
  rescue
13
- log.fatal("Advice you to use not system ruby \n" \
12
+ Log.error("Advice you to use not system ruby \n" \
14
13
  'For more info read: https://github.com/alter-al/' \
15
14
  'skeleton/blob/master/docs/permissions_error.md')
16
- raise
17
- end
18
-
19
- def log
20
- create_logger if @log.nil?
21
- @log
22
15
  end
23
16
 
24
17
  def skeletoner; end
25
18
 
19
+ def devices; end
20
+
26
21
  def clear
27
22
  FileUtils.rm_rf(PAGE_OBJECTS_FOLDER)
28
23
  FileUtils.rm_rf(ATTACHMENTS_FOLDER)
@@ -35,14 +30,6 @@ class Base
35
30
  File.open(file_path, 'a') { |f| f.write(code) }
36
31
  end
37
32
 
38
- def create_logger
39
- @log = Logger.new(STDOUT)
40
- @log.level = Logger::INFO
41
- @log.formatter = proc do |severity, datetime, _progname, msg|
42
- "[#{severity}] #{datetime}: " + "#{msg}\n".colorize(:light_cyan)
43
- end
44
- end
45
-
46
33
  def snake_style(method_name)
47
34
  method_name
48
35
  .tr("@()[]'\"*!?{}:;#$^.,\/\\", '')
data/lib/skeleton/ios.rb CHANGED
@@ -16,28 +16,36 @@ class IOS < Base
16
16
  XCRESULTS_FOLDER = "#{ROOT_DIR}/XCResults".freeze
17
17
  XCODEPROJ_FOLDER = "#{ROOT_DIR}/xcodeproj".freeze
18
18
 
19
- attr_accessor :platform, :udid, :bundle_id
19
+ attr_accessor :udid, :bundle_id
20
20
 
21
21
  def initialize(options)
22
- self.platform = options.platform
23
22
  self.udid = options.udid
24
23
  self.bundle_id = options.bundle
25
24
  @language = Language.new
26
25
  end
27
26
 
28
27
  def skeletoner
29
- log.info('We starting to skeleton your screen 🚀')
30
28
  check_udid
31
29
  check_bundle
30
+ Log.info('We starting to skeleton your screen 🚀')
32
31
  page_source
33
32
  create_page_objects
34
33
  save_screenshot
35
34
  save(code: page_source)
36
- log.info('We successfully skeletoned your screen 👻')
35
+ Log.info('We successfully skeletoned your screen 👻')
36
+ end
37
+
38
+ def devices
39
+ `idevice_id -l`.split.uniq.map { |d| d }
37
40
  end
38
41
 
39
42
  private
40
43
 
44
+ def bundle_id=(bundle_id)
45
+ raise 'Not set bundle_id [-b arg]' if bundle_id.nil?
46
+ @bundle_id = bundle_id
47
+ end
48
+
41
49
  def create_locator(line)
42
50
  locator_by_id = locator_by_id(line)
43
51
  locator_by_label = locator_by_label(line)
@@ -65,7 +73,7 @@ class IOS < Base
65
73
  end
66
74
 
67
75
  def create_page_objects
68
- log.info('Generation page objects for your awesome language 💪')
76
+ Log.info('Generation page objects for your awesome language 💪')
69
77
  page_source.each_line do |line|
70
78
  break if line.include?(' StatusBar, ')
71
79
  next if line.include?('Application, ')
@@ -123,7 +131,7 @@ class IOS < Base
123
131
 
124
132
  def page_source
125
133
  if @page_source.nil?
126
- log.info('Getting screen source tree ⚒')
134
+ Log.info('Getting screen source tree ⚒')
127
135
  FileUtils.rm_rf(XCRESULTS_FOLDER)
128
136
  start_grep = 'start_grep_tag'
129
137
  end_grep = 'end_grep_tag'
@@ -138,27 +146,16 @@ class IOS < Base
138
146
  @page_source.slice!(start_grep)
139
147
  @page_source.slice!(end_grep)
140
148
  if @page_source.empty?
141
- log.fatal("Try to sign Skeleton and SkeletonUI targets in " \
149
+ Log.error("Try to sign Skeleton and SkeletonUI targets in " \
142
150
  "#{XCODEPROJ_FOLDER}/Skeleton.xcodeproj \n" \
143
151
  'For more info read: https://github.com/alter-al/' \
144
152
  'skeleton/blob/master/docs/real-ios-device-config.md')
145
- raise
146
153
  end
147
- log.info('Successfully getting Screen Source Tree 🔥')
154
+ Log.info('Successfully getting Screen Source Tree 🔥')
148
155
  end
149
156
  @page_source
150
157
  end
151
158
 
152
- def check_udid
153
- return unless @simulator.nil?
154
- log.info('Checking iOS UDID 👨‍💻')
155
- simulators = `xcrun simctl list`
156
- @simulator = simulators.include?(@udid)
157
- return if @simulator || `instruments -s devices`.include?(@udid)
158
- log.fatal("No such devices with UDID: #{@udid}")
159
- raise
160
- end
161
-
162
159
  def check_bundle
163
160
  if @simulator
164
161
  return if `xcrun simctl appinfo #{@udid} #{@bundle_id}`
@@ -167,16 +164,26 @@ class IOS < Base
167
164
  return if `ideviceinstaller -u #{@udid} -l`
168
165
  .include?("#{@bundle_id},")
169
166
  end
170
- log.fatal("No such apps with bundle_id: #{@bundle_id}")
171
- raise
167
+ Log.error("No such apps with bundle_id: #{@bundle_id}")
172
168
  end
173
169
 
174
170
  def save_screenshot
175
- log.info('Saving screenshot 📷')
171
+ Log.info('Saving screenshot 📷')
176
172
  png_path = "#{XCRESULTS_FOLDER}/Attachments/*.png"
177
- new_path = "#{ATTACHMENTS_FOLDER}/#{@platform}_#{TIMESTAMP}.png"
173
+ new_path = "#{ATTACHMENTS_FOLDER}/ios_#{TIMESTAMP}.png"
178
174
  screenshots = Dir[png_path].collect { |png| File.expand_path(png) }
179
175
  FileUtils.cp(screenshots[0], new_path)
180
176
  FileUtils.rm_rf(XCRESULTS_FOLDER)
181
177
  end
178
+
179
+ def check_udid
180
+ return unless @simulator.nil?
181
+ Log.info('Checking device udid 👨‍💻')
182
+ @simulator = `xcrun simctl list`.include?(@udid) unless @udid.nil?
183
+ @udid = devices.first if @udid.nil? && devices.size == 1
184
+ Log.error("Provide device udid [-u]") if @udid.nil?
185
+ unless @simulator || devices.include?(@udid)
186
+ Log.error("No such devices with udid: #{@udid}")
187
+ end
188
+ end
182
189
  end
@@ -0,0 +1,14 @@
1
+ class Log
2
+ def self.info(message)
3
+ puts "[INFO] #{Time.now}: #{message}".colorize(:light_cyan)
4
+ end
5
+
6
+ def self.warn(message)
7
+ puts "[WARN] #{Time.now}: #{message}".colorize(:light_yellow)
8
+ end
9
+
10
+ def self.error(message)
11
+ puts "[ERROR] #{Time.now}: #{message}".colorize(:light_red)
12
+ Process.exit(1)
13
+ end
14
+ end
data/lib/skeleton/root.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  require_relative 'version'
2
2
 
3
3
  class Base
4
- # ROOT_DIR = File.expand_path('..', Dir.pwd)
5
4
  ROOT_DIR = "#{`gem environment gemdir`.strip}" \
6
- "/gems/#{Skeleton::GEM_NAME}-#{Skeleton::VERSION}"
5
+ "/gems/#{Skeleton::GEM_NAME}-#{Skeleton::VERSION}".freeze
7
6
  end
@@ -1,4 +1,4 @@
1
1
  module Skeleton
2
- VERSION = '0.1.9'
3
- GEM_NAME = 'skeleton-ui'
2
+ VERSION ||= '0.1.11'.freeze
3
+ GEM_NAME ||= 'skeleton-ui'.freeze
4
4
  end
File without changes
@@ -4,7 +4,7 @@ require_relative '../lib/skeleton/root'
4
4
  server_port = ARGV[0]
5
5
  set :port, server_port
6
6
 
7
- File.open("#{Base::ROOT_DIR}/html/port", 'w+') { |f| f.write(server_port) }
7
+ File.open("#{Base::ROOT_DIR}/server/port", 'w+') { |f| f.write(server_port) }
8
8
 
9
9
  get '/' do
10
10
  redirect "skeleton"
@@ -13,11 +13,11 @@ end
13
13
  get '/:file' do
14
14
  domain = params[:file].split('.').last
15
15
  file = domain == params[:file] ? "#{domain}.html" : params[:file]
16
- send_file "#{Base::ROOT_DIR}/html/#{file}"
16
+ send_file "#{Base::ROOT_DIR}/server/#{file}"
17
17
  end
18
18
 
19
19
  post '/:file' do
20
20
  domain = params[:file].split('.').last
21
21
  file = domain == params[:file] ? "#{domain}.html" : params[:file]
22
- send_file "#{Base::ROOT_DIR}/html/#{file}"
22
+ send_file "#{Base::ROOT_DIR}/server/#{file}"
23
23
  end
File without changes
File without changes
@@ -354,7 +354,7 @@
354
354
  buildSettings = {
355
355
  ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
356
356
  CODE_SIGN_STYLE = Automatic;
357
- DEVELOPMENT_TEAM = 4D6LA585PP;
357
+ DEVELOPMENT_TEAM = "";
358
358
  INFOPLIST_FILE = Skeleton/Info.plist;
359
359
  IPHONEOS_DEPLOYMENT_TARGET = 9.0;
360
360
  LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@@ -370,7 +370,7 @@
370
370
  buildSettings = {
371
371
  ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
372
372
  CODE_SIGN_STYLE = Automatic;
373
- DEVELOPMENT_TEAM = 4D6LA585PP;
373
+ DEVELOPMENT_TEAM = "";
374
374
  INFOPLIST_FILE = Skeleton/Info.plist;
375
375
  IPHONEOS_DEPLOYMENT_TARGET = 9.0;
376
376
  LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@@ -386,7 +386,7 @@
386
386
  buildSettings = {
387
387
  ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
388
388
  CODE_SIGN_STYLE = Automatic;
389
- DEVELOPMENT_TEAM = 4D6LA585PP;
389
+ DEVELOPMENT_TEAM = "";
390
390
  INFOPLIST_FILE = SkeletonUITests/Info.plist;
391
391
  LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
392
392
  PRODUCT_BUNDLE_IDENTIFIER = ru.forqa.SkeletonUITests;
@@ -402,7 +402,7 @@
402
402
  buildSettings = {
403
403
  ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
404
404
  CODE_SIGN_STYLE = Automatic;
405
- DEVELOPMENT_TEAM = 4D6LA585PP;
405
+ DEVELOPMENT_TEAM = "";
406
406
  INFOPLIST_FILE = SkeletonUITests/Info.plist;
407
407
  LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
408
408
  PRODUCT_BUNDLE_IDENTIFIER = ru.forqa.SkeletonUITests;
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: skeleton-ui
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.1.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - a.alterpesotskiy
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-07-27 00:00:00.000000000 Z
11
+ date: 2018-08-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -161,17 +161,18 @@ files:
161
161
  - docs/real-ios-device-config.md
162
162
  - docs/sign_xcproj.png
163
163
  - docs/untrusted-dev.png
164
- - html/index.css
165
- - html/server.rb
166
- - html/skeleton.html
167
- - html/template.html.erb
168
164
  - lib/skeleton.rb
169
165
  - lib/skeleton/android.rb
170
166
  - lib/skeleton/base.rb
171
167
  - lib/skeleton/ios.rb
172
168
  - lib/skeleton/languages.rb
169
+ - lib/skeleton/logger.rb
173
170
  - lib/skeleton/root.rb
174
171
  - lib/skeleton/version.rb
172
+ - server/index.css
173
+ - server/server.rb
174
+ - server/skeleton.html
175
+ - server/template.html.erb
175
176
  - skeleton.gemspec
176
177
  - xcodeproj/Skeleton.xcodeproj/project.pbxproj
177
178
  - xcodeproj/Skeleton.xcodeproj/project.xcworkspace/contents.xcworkspacedata