talk 2.0.1 → 2.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.
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