Class: Terrestrial::Cli::Parser::Storyboard

Inherits:
Object
  • Object
show all
Includes:
REXML
Defined in:
lib/terrestrial/cli/parser/storyboard.rb

Constant Summary collapse

LANGUAGE =
:ios_storyboard
QUERIES =
{
  "storyboard-label" => "//label",
  "storyboard-text-field" => "//textField",
  "storyboard-button" => "//button/state",
  "storyboard-bar-button-item" => "//barButtonItem",
  "storyboard-navbar-item" => "//navigationItem",
  "storyboard-text-view" => "//textView"
}
TEXT_ATTRIBUTE =
{
  "storyboard-label" => "text",
  "storyboard-text-field" => "placeholder",
  "storyboard-button" => "title",
  "storyboard-bar-button-item" => "title",
  "storyboard-navbar-item" => "title",
  "storyboard-text-view" => "text"
}
TYPES =
QUERIES.keys

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file) ⇒ Storyboard

Returns a new instance of Storyboard.



31
32
33
34
35
36
# File 'lib/terrestrial/cli/parser/storyboard.rb', line 31

def initialize(file)
  @path = file
  @file = File.new(file)
  @document = Document.new(@file)
  @result = []
end

Instance Attribute Details

#resultObject (readonly)

Returns the value of attribute result.



8
9
10
# File 'lib/terrestrial/cli/parser/storyboard.rb', line 8

def result
  @result
end

Class Method Details

.find_api_calls(file) ⇒ Object



42
43
44
# File 'lib/terrestrial/cli/parser/storyboard.rb', line 42

def self.find_api_calls(file)
  self.new(file).find_api_calls
end

.find_strings(file) ⇒ Object



38
39
40
# File 'lib/terrestrial/cli/parser/storyboard.rb', line 38

def self.find_strings(file)
  self.new(file).find_strings
end

Instance Method Details

#api_calls_queryObject



125
126
127
128
129
130
131
132
133
134
135
# File 'lib/terrestrial/cli/parser/storyboard.rb', line 125

def api_calls_query
  # Finds all the attributes that say that an element is 
  # translated by Terrestrial, and we then traverse
  # two parents up:
  #
  # <*targetElement*>
  #   <userDefinedRuntimeAttributes>
  #     <userDefinedRuntimeAttribute ... />   <- these are what we find

  '//userDefinedRuntimeAttribute[@type="boolean" and @value="YES"]/../..'
end

#build_registry_entry_hash(string, context, type) ⇒ Object



153
154
155
156
157
158
159
160
161
162
# File 'lib/terrestrial/cli/parser/storyboard.rb', line 153

def build_registry_entry_hash(string, context, type)
  Hash.new.tap do |entry|
    entry["string"] = string.to_s
    entry["language"] = LANGUAGE
    entry["context"] = context || ""
    entry["file"] = @path
    entry["line_number"] = nil
    entry["type"] = type
  end
end

#find_api_callsObject



46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/terrestrial/cli/parser/storyboard.rb', line 46

def find_api_calls
  labels = []
  XPath.each(@document, api_calls_query) do |node|
    type    = type_for(node.name)
    string  = get_string(node)
    context = get_context(node)

    labels << build_registry_entry_hash(string, context, type)
  end
  @result = labels
  @result
end

#find_entries_for_type(type) ⇒ Object



79
80
81
82
83
84
85
86
87
# File 'lib/terrestrial/cli/parser/storyboard.rb', line 79

def find_entries_for_type(type)
  labels = []
  XPath.each(@document, QUERIES[type]) do |node|
    labels << new_entry(node.attributes[TEXT_ATTRIBUTE[type]], 
                            type: type, 
                              id: get_id(node))
  end
  labels
end

#find_stringsObject



59
60
61
62
63
64
# File 'lib/terrestrial/cli/parser/storyboard.rb', line 59

def find_strings
  TYPES.each do |type|
    @result.concat(find_entries_for_type(type))
  end
  @result
end

#get_context(node) ⇒ Object



106
107
108
109
110
111
112
113
114
# File 'lib/terrestrial/cli/parser/storyboard.rb', line 106

def get_context(node)
  # //textView/userDefinedRuntimeAttributes/userDefinedRuntimeAttribute[@keyPath="contextInfo"]
  context = ""
  attributes = node.elements.select {|e| e.name == "userDefinedRuntimeAttributes"}.first
  attributes.each_element_with_attribute("keyPath", "contextInfo") do |e| 
    context = e.attributes["value"]
  end
  context
end

#get_id(node) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/terrestrial/cli/parser/storyboard.rb', line 89

def get_id(node)
  # Why? Because the button's text is not in the
  # button, but in a child element, that doesn't have
  # an ID. So for most situations you'll just pick the
  # ID off the element, but sometimes we'll have to 
  # traverse back up to get the ID. If that element
  # doesn't have an ID, it's a new situation and
  # we should get an exception down the line.

  target = node
  if target.attributes["id"].nil?
    target.parent.attributes["id"]
  else
    target.attributes["id"]
  end
end

#get_string(node) ⇒ Object



116
117
118
119
120
121
122
123
# File 'lib/terrestrial/cli/parser/storyboard.rb', line 116

def get_string(node)
  type = type_for(node.name)
  if type == "storyboard-button"
    node.elements.select {|e| e.name == "state"}.first.attributes[TEXT_ATTRIBUTE[type]]
  else
    node.attributes[TEXT_ATTRIBUTE[type]]
  end
end

#new_entry(string, opts) ⇒ Object



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/terrestrial/cli/parser/storyboard.rb', line 137

def new_entry(string, opts)
  defaults = { type: "storyboard" }
  values = defaults.merge(opts)

  Hash.new.tap do |entry|
    entry["file"] = @path
    entry["language"] = LANGUAGE
    entry["string"] = string.to_s
    entry["type"] = values.fetch(:type)
    entry["line_number"] = nil
    entry["metadata"] = {
      "storyboard_element_id" => values.fetch(:id)
    }
  end
end

#type_for(name) ⇒ Object



68
69
70
71
72
73
74
75
76
77
# File 'lib/terrestrial/cli/parser/storyboard.rb', line 68

def type_for(name)
  {
    "label"          => "storyboard-label",
    "textField"      => "storyboard-text-field",
    "button"         => "storyboard-button",
    "barButtonItem"  => "storyboard-bar-button-item",
    "navigationItem" => "storyboard-navbar-item",
    "textView"       => "storyboard-text-view",
  }[name]
end