talk 2.0.1 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/.travis.yml +6 -0
  4. data/Gemfile +10 -0
  5. data/README.md +6 -0
  6. data/Rakefile +9 -0
  7. data/features/class-field.feature +226 -0
  8. data/features/class.feature +95 -0
  9. data/features/enumeration-constant.feature +76 -0
  10. data/features/enumeration.feature +35 -0
  11. data/features/glossary-term.feature +46 -0
  12. data/features/glossary.feature +35 -0
  13. data/features/step_definitions/class-field.rb +74 -0
  14. data/features/step_definitions/class.rb +50 -0
  15. data/features/step_definitions/enumeration-constant.rb +42 -0
  16. data/features/step_definitions/enumeration.rb +29 -0
  17. data/features/step_definitions/glossary-term.rb +31 -0
  18. data/features/step_definitions/glossary.rb +23 -0
  19. data/features/support/env.rb +261 -0
  20. data/lib/context.rb +282 -0
  21. data/lib/context_class.rb +224 -0
  22. data/lib/contexts/README.md +274 -0
  23. data/lib/contexts/base.rb +6 -0
  24. data/lib/contexts/boolean.rb +5 -0
  25. data/lib/contexts/class.rb +11 -0
  26. data/lib/contexts/constant.rb +5 -0
  27. data/lib/contexts/enumeration.rb +20 -0
  28. data/lib/contexts/field.rb +47 -0
  29. data/lib/contexts/glossary.rb +7 -0
  30. data/lib/contexts/inherits.rb +3 -0
  31. data/lib/contexts/map.rb +7 -0
  32. data/lib/contexts/meta.rb +2 -0
  33. data/lib/contexts/method.rb +15 -0
  34. data/lib/contexts/numeric.rb +5 -0
  35. data/lib/contexts/protocol.rb +8 -0
  36. data/lib/contexts/reference.rb +6 -0
  37. data/lib/contexts/string.rb +5 -0
  38. data/lib/contexts/target.rb +11 -0
  39. data/lib/contexts/term.rb +11 -0
  40. data/lib/languages/java/java.rb +145 -0
  41. data/lib/languages/java/templates/class.java.erb +22 -0
  42. data/lib/languages/java/templates/enumeration.java.erb +10 -0
  43. data/lib/languages/java/templates/glossary.java.erb +8 -0
  44. data/lib/languages/language.rb +172 -0
  45. data/lib/languages/objc/objc.rb +162 -0
  46. data/lib/languages/objc/templates/TalkClasses.h.erb +3 -0
  47. data/lib/languages/objc/templates/TalkClassesForward.h.erb +2 -0
  48. data/lib/languages/objc/templates/TalkConstants.h.erb +22 -0
  49. data/lib/languages/objc/templates/TalkObjectList.h.erb +4 -0
  50. data/lib/languages/objc/templates/class.h.erb +21 -0
  51. data/lib/languages/objc/templates/class.m.erb +43 -0
  52. data/lib/parse_error.rb +4 -0
  53. data/lib/parser.rb +119 -0
  54. data/lib/registry.rb +151 -0
  55. data/lib/talk.rb +5 -0
  56. data/talk.gemspec +18 -0
  57. metadata +71 -3
@@ -0,0 +1,3 @@
1
+ <%= autogenerated_warning %>
2
+ #import "TalkObject.h"
3
+ <%= (@base[:class].map { |cls| "#import \"#{truncated_name(cls)}.h\"" }).join("\n") %>
@@ -0,0 +1,2 @@
1
+ <%= autogenerated_warning %>
2
+ <%= (@base[:class].map { |cls| "@class #{truncated_name(cls)}; // #{definition_reference(cls)}" }).join("\n") %>
@@ -0,0 +1,22 @@
1
+ <%= autogenerated_warning %>
2
+ <% @base[:glossary].each do |glossary| %>
3
+
4
+ // @glossary <%= glossary[:name] %>
5
+ <%= comment_block(glossary) %>
6
+
7
+ <% glossary[:term].each do |term| %>
8
+ <%= comment_block(term) %>
9
+ #define <%= glossary_term_name(term[:name]) %> @"<%= term[:value] %>"
10
+ <% end # term %>
11
+
12
+ <% end # glossary %>
13
+
14
+ <% @base[:enumeration].each do |enumeration| %>
15
+
16
+ <%= comment_block(enumeration) %>
17
+ enum <%= truncated_name(enumeration[:name]) %>
18
+ {
19
+ <%= (enumeration[:constant].map { |constant| "\t"+constant_definition(constant) }).join("\n") %>
20
+ };
21
+
22
+ <% end # enumeration %>
@@ -0,0 +1,4 @@
1
+ <%= autogenerated_warning %>
2
+ #import "TalkConstants.h"
3
+ #import "TalkClassesForward.h"
4
+ #import "TalkClasses.h"
@@ -0,0 +1,21 @@
1
+ <%= autogenerated_warning %>
2
+ #import "TalkObjectList.h"
3
+
4
+ <%= comment_block(@current_class) %>
5
+ @interface <%= "#{truncated_name(@current_class)}" %> : <%= "#{superclass(@current_class)}" %>
6
+ {
7
+ <%=
8
+ lines = []
9
+ @current_class[:field].each do |field|
10
+ lines.push comment_block(field, 1)
11
+ lines.push "\t"+field_definition(@current_class, field) + "; // " + field[:type].join('')
12
+ lines.push ""
13
+ end
14
+
15
+ lines.join("\n")
16
+ %>}
17
+
18
+ <%= (@current_class[:field].map { |f| "@property #{field_tags(f)} #{field_definition(@current_class, f)};" }).join("\n") %>
19
+ +(NSString *) fullyQualifiedClassName;
20
+
21
+ @end
@@ -0,0 +1,43 @@
1
+ <%= autogenerated_warning %>
2
+ #define __CANONFILE__ "<%= truncated_name(@current_class) %>"
3
+ #import "TalkObjectList.h"
4
+ #import "TalkObject+Private.h"
5
+
6
+ #if ! __has_feature(objc_arc)
7
+ #error This file requires Automatic Reference Counting
8
+ #endif
9
+
10
+ @implementation <%= truncated_name(@current_class) %>
11
+ <%= dynamic_body_for_named_wrapper %>
12
+ <% unless trimmed_fields(@current_class).empty? then %>
13
+ @synthesize <%= (trimmed_fields(@current_class).map { |f| mapped_name(@current_class, f[:name], :field) }).join(', ') %>;
14
+ <% end %>
15
+
16
+ -(void) initKeymaps
17
+ {
18
+ [super initKeymaps];
19
+ <% @target[:map].each do |map|
20
+ next unless map[:class_name] == truncated_name(@current_class[:name])%>
21
+ [self mapSerializedKey:@"<%= map[:field_name] %>" toLocalKey:@"<%= map[:new_field_name] %>"];
22
+ <% end %>}
23
+
24
+ <% unless (@current_class[:field].reject { |f| assist_line(f).nil? }).length == 0 then %>
25
+ -(NSString *) containerStructureForLocalKey: (NSString *) localKey
26
+ {<%
27
+ @current_class[:field].each do |field|
28
+ assist = assist_line(field)
29
+ unless assist.nil? %>
30
+ if([localKey isEqualToString:@"<%= mapped_name(@current_class, field[:name], :field) %>"]) return @"<%= assist %>";
31
+ <%
32
+ end
33
+ end
34
+ %>
35
+ return [super containerStructureForLocalKey:localKey];
36
+ }
37
+ <% end %>
38
+ +(NSString *) fullyQualifiedClassName
39
+ {
40
+ return @"<%= @current_class[:name] %>";
41
+ }
42
+
43
+ @end
@@ -0,0 +1,4 @@
1
+ module Talk
2
+ class ParseError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,119 @@
1
+ require "parse_error.rb"
2
+ require "context"
3
+
4
+ module Talk
5
+ attr_reader :contexts, :finalized
6
+
7
+ @contexts = {}
8
+
9
+ class Parser
10
+ attr_accessor :basepath
11
+
12
+ def self.error(tag, file, line, message)
13
+ near_msg = tag.nil? ? "" : " near @#{tag}"
14
+ raise ParseError, "#{file}:#{line} parse error#{near_msg}: #{message}"
15
+ end
16
+
17
+ def initialize
18
+ @contexts = [ Context.context_for_name(:base).new("base", "n/a", "0") ]
19
+ @base = @contexts.first
20
+ @finalized = false
21
+ @closed_contexts = []
22
+ end
23
+
24
+ # signal that we are done parsing files, and it is time to do final validation
25
+ def finalize
26
+ close_active_context until @contexts.empty?
27
+ @closed_contexts.each { |ctx| ctx.finalize }
28
+ finalized = true
29
+ end
30
+
31
+ def results
32
+ finalize unless @finalized
33
+ @base.to_h
34
+ end
35
+
36
+ def trim_filename(filename)
37
+ if @basepath.nil? == false and filename.start_with? @basepath then
38
+ filename = filename[@basepath.length .. -1]
39
+ filename = filename[1..-1] while filename.start_with? "/"
40
+ end
41
+
42
+ filename
43
+ end
44
+
45
+ def parse_file(filename)
46
+ parse(filename, IO.read(filename))
47
+ end
48
+
49
+ def parse(filename, contents)
50
+ contents = contents.split("\n") unless contents.is_a? Array
51
+ contents.each_with_index { |line, line_num| parse_line(line.strip.split, filename, line_num+1) }
52
+ end
53
+
54
+ def parse_line(words, file, line)
55
+ return if line_is_comment?(words)
56
+
57
+ @file = trim_filename(file)
58
+ @line = line
59
+ words.each { |word| parse_word(word) }
60
+ end
61
+
62
+ def parse_word(word)
63
+ @word = word
64
+
65
+ if word_is_tag?(word) then
66
+ parse_tag(identifier_from_tag_word(word))
67
+ else
68
+ @contexts.last.parse(word, @file, @line)
69
+ end
70
+ end
71
+
72
+ def parse_tag(tag)
73
+ @tag = tag
74
+ @contexts.last.has_tag?(tag) ? parse_supported_tag : parse_unsupported_tag
75
+ end
76
+
77
+ def parse_supported_tag
78
+ new_context = @contexts.last.start_tag(@tag, @file, @line)
79
+ if new_context.nil? then
80
+ close_active_context
81
+ else
82
+ @contexts.push new_context
83
+ @closed_contexts.push new_context
84
+ end
85
+ end
86
+
87
+ def parse_unsupported_tag
88
+ stack = Array.new(@contexts)
89
+ stack.pop until stack.empty? or stack.last.has_tag? @tag
90
+
91
+ parse_error("tag not supported in @#{@contexts.last.tag.to_s}") if stack.empty?
92
+
93
+ close_active_context until @contexts.last == stack.last
94
+
95
+ parse_supported_tag
96
+ end
97
+
98
+ def close_active_context
99
+ @closed_contexts.push @contexts.pop
100
+ @contexts.last.end_tag(@closed_contexts.last) unless @contexts.empty?
101
+ end
102
+
103
+ def word_is_tag?(word)
104
+ word[0] == '@'
105
+ end
106
+
107
+ def identifier_from_tag_word(word)
108
+ word[1..-1].to_sym
109
+ end
110
+
111
+ def line_is_comment?(line)
112
+ line.length > 0 and line[0].length > 0 and line[0][0] == '#'
113
+ end
114
+
115
+ def parse_error(message)
116
+ raise Talk::Parser.error(@tag, @file, @line, message)
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,151 @@
1
+ class Array
2
+ def each_prefix
3
+ self.length.times do |i|
4
+ yield(self[0..i])
5
+ end
6
+ end
7
+ end
8
+
9
+ module Talk
10
+ class RegistryEntry
11
+ attr_reader :file, :line, :name
12
+
13
+ def initialize(name=nil, file=nil, line=nil)
14
+ @file = file
15
+ @line = line
16
+ @name = name
17
+ @children = {}
18
+ end
19
+
20
+ def make_entry(name, file, line)
21
+ @name = name
22
+ @file = file
23
+ @line = line
24
+ end
25
+
26
+ def [](key)
27
+ @children[key]
28
+ end
29
+
30
+ def []=(key, value)
31
+ @children[key] = value
32
+ end
33
+
34
+ def keys
35
+ @children.keys
36
+ end
37
+
38
+ def each(&block)
39
+ @children.each &block
40
+ end
41
+
42
+ def has_children?
43
+ not @children.empty?
44
+ end
45
+
46
+ def is_entry?
47
+ @file != nil
48
+ end
49
+
50
+ def to_s
51
+ is_entry? ? "#{@file}:#{@line}" : "container"
52
+ end
53
+ end
54
+
55
+ class Registry
56
+ class << self
57
+ def add(name, namespace, file, line, delimiter=nil)
58
+ if registered?(name, namespace) then
59
+ old_reg = get_registrations(name, namespace).last
60
+ Talk::Parser.error(nil, file, line, "Duplicate registration #{name} in #{namespace}; previously defined at #{old_reg}")
61
+ end
62
+
63
+ @registry ||= {}
64
+ @registry[namespace] ||= {}
65
+ split_name = delimiter.nil? ? [*name] : name.to_s.split(delimiter)
66
+
67
+ # create each level of the split name
68
+ level = @registry[namespace]
69
+ split_name[0..-2].each do |component| # all but the last component
70
+ level[component] ||= RegistryEntry.new
71
+ level = level[component]
72
+ end
73
+
74
+ level[split_name.last] ||= RegistryEntry.new(name, file, line)
75
+ level[split_name.last].make_entry(name, file, line) # in case it already existed as a container
76
+ add_reverse_lookup(split_name, namespace, level[split_name.last], delimiter)
77
+ end
78
+
79
+ def add_reverse_lookup(split_name, namespace, entry, delimiter)
80
+ @reverse ||= {}
81
+ @reverse[namespace] ||= {}
82
+ split_name.reverse.each_prefix do |prefix|
83
+ name = prefix.reverse.join(delimiter)
84
+ @reverse[namespace][name] ||= []
85
+ @reverse[namespace][name].push entry
86
+ end
87
+ end
88
+
89
+ def get_registrations(name, namespace, match_exact = false)
90
+ @registry ||= {}
91
+ exact = get_exact_registrations(name, namespace)
92
+
93
+ return exact unless exact.empty?
94
+ return [] if match_exact
95
+
96
+ get_inexact_registrations(name, namespace)
97
+ end
98
+
99
+ def get_exact_registrations(name, namespace)
100
+ level = @registry[namespace]
101
+ [*name].each do |component|
102
+ return [] if level.nil?
103
+ level = level[component]
104
+ end
105
+
106
+ return [*level] if not level.nil? and level.is_entry?
107
+ []
108
+ end
109
+
110
+ def get_inexact_registrations(name, namespace)
111
+ return [] if @reverse.nil? or @reverse[namespace].nil? or @reverse[namespace][name].nil?
112
+ @reverse[namespace][name]
113
+ end
114
+
115
+ def registered?(name, namespace, match_exact = false)
116
+ not get_registrations(name, namespace, match_exact).empty?
117
+ end
118
+
119
+ def render_level(level, at_depth=1)
120
+ indent = " "*at_depth
121
+ s = ""
122
+ level.keys.sort.each do |key|
123
+ value = level[key]
124
+ s += indent + key
125
+ s += " (entry from #{File.basename(value.file)}:#{value.line})" if value.is_entry?
126
+ s += "\n"
127
+ s += render_level(value, at_depth+1)
128
+ end
129
+
130
+ s
131
+ end
132
+
133
+ def reset
134
+ @registry = nil
135
+ @reverse = nil
136
+ end
137
+
138
+ def to_s
139
+ return "Empty registry" if @registry.nil? or @registry.empty?
140
+ s = ""
141
+ @registry.keys.sort.each do |namespace|
142
+ level = @registry[namespace]
143
+ s += "Namespace #{namespace}:\n"
144
+ s += render_level(level)
145
+ end
146
+
147
+ s
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'parser'
4
+ require 'languages/language.rb'
5
+
@@ -0,0 +1,18 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'talk'
3
+ s.executables << 'talk'
4
+ s.version = '2.0.2'
5
+ s.date = '2014-05-14'
6
+ s.summary = "Compile-to-source protocol contract specification language"
7
+ s.description = "A lightweight language for specifying protocol contracts. Compiles to source in Java, Javascript, ObjC and Ruby."
8
+ s.authors = ["Jonas Acres"]
9
+ s.email = 'jonas@becuddle.com'
10
+ s.homepage = 'http://github.com/jonasacres/talk'
11
+ s.license = 'GPLv2'
12
+
13
+ s.files = `git ls-files`.split($/)
14
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
15
+ s.test_files = s.files.grep(%r{^(test|s|features)/})
16
+ s.require_paths = ["lib"]
17
+
18
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: talk
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonas Acres
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-13 00:00:00.000000000 Z
11
+ date: 2014-05-14 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A lightweight language for specifying protocol contracts. Compiles to
14
14
  source in Java, Javascript, ObjC and Ruby.
@@ -18,7 +18,62 @@ executables:
18
18
  extensions: []
19
19
  extra_rdoc_files: []
20
20
  files:
21
+ - .gitignore
22
+ - .travis.yml
23
+ - Gemfile
24
+ - README.md
25
+ - Rakefile
21
26
  - bin/talk
27
+ - features/class-field.feature
28
+ - features/class.feature
29
+ - features/enumeration-constant.feature
30
+ - features/enumeration.feature
31
+ - features/glossary-term.feature
32
+ - features/glossary.feature
33
+ - features/step_definitions/class-field.rb
34
+ - features/step_definitions/class.rb
35
+ - features/step_definitions/enumeration-constant.rb
36
+ - features/step_definitions/enumeration.rb
37
+ - features/step_definitions/glossary-term.rb
38
+ - features/step_definitions/glossary.rb
39
+ - features/support/env.rb
40
+ - lib/context.rb
41
+ - lib/context_class.rb
42
+ - lib/contexts/README.md
43
+ - lib/contexts/base.rb
44
+ - lib/contexts/boolean.rb
45
+ - lib/contexts/class.rb
46
+ - lib/contexts/constant.rb
47
+ - lib/contexts/enumeration.rb
48
+ - lib/contexts/field.rb
49
+ - lib/contexts/glossary.rb
50
+ - lib/contexts/inherits.rb
51
+ - lib/contexts/map.rb
52
+ - lib/contexts/meta.rb
53
+ - lib/contexts/method.rb
54
+ - lib/contexts/numeric.rb
55
+ - lib/contexts/protocol.rb
56
+ - lib/contexts/reference.rb
57
+ - lib/contexts/string.rb
58
+ - lib/contexts/target.rb
59
+ - lib/contexts/term.rb
60
+ - lib/languages/java/java.rb
61
+ - lib/languages/java/templates/class.java.erb
62
+ - lib/languages/java/templates/enumeration.java.erb
63
+ - lib/languages/java/templates/glossary.java.erb
64
+ - lib/languages/language.rb
65
+ - lib/languages/objc/objc.rb
66
+ - lib/languages/objc/templates/TalkClasses.h.erb
67
+ - lib/languages/objc/templates/TalkClassesForward.h.erb
68
+ - lib/languages/objc/templates/TalkConstants.h.erb
69
+ - lib/languages/objc/templates/TalkObjectList.h.erb
70
+ - lib/languages/objc/templates/class.h.erb
71
+ - lib/languages/objc/templates/class.m.erb
72
+ - lib/parse_error.rb
73
+ - lib/parser.rb
74
+ - lib/registry.rb
75
+ - lib/talk.rb
76
+ - talk.gemspec
22
77
  homepage: http://github.com/jonasacres/talk
23
78
  licenses:
24
79
  - GPLv2
@@ -43,4 +98,17 @@ rubygems_version: 2.0.14
43
98
  signing_key:
44
99
  specification_version: 4
45
100
  summary: Compile-to-source protocol contract specification language
46
- test_files: []
101
+ test_files:
102
+ - features/class-field.feature
103
+ - features/class.feature
104
+ - features/enumeration-constant.feature
105
+ - features/enumeration.feature
106
+ - features/glossary-term.feature
107
+ - features/glossary.feature
108
+ - features/step_definitions/class-field.rb
109
+ - features/step_definitions/class.rb
110
+ - features/step_definitions/enumeration-constant.rb
111
+ - features/step_definitions/enumeration.rb
112
+ - features/step_definitions/glossary-term.rb
113
+ - features/step_definitions/glossary.rb
114
+ - features/support/env.rb