reactrb 0.8.3 → 0.8.4

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.
@@ -0,0 +1,57 @@
1
+ module React
2
+ module Component
3
+ module DslInstanceMethods
4
+ def children
5
+ if `#{@native}.props.children==undefined`
6
+ nodes = []
7
+ else
8
+ nodes = [`#{@native}.props.children`].flatten
9
+ end
10
+ class << nodes
11
+ include Enumerable
12
+
13
+ def to_n
14
+ self
15
+ end
16
+
17
+ def each(&block)
18
+ if block_given?
19
+ %x{
20
+ React.Children.forEach(#{self.to_n}, function(context){
21
+ #{yield React::Element.new(`context`)}
22
+ })
23
+ }
24
+ nil
25
+ else
26
+ Enumerator.new(`React.Children.count(#{self.to_n})`) do |y|
27
+ %x{
28
+ React.Children.forEach(#{self.to_n}, function(context){
29
+ #{y << Element.new(`context`)}
30
+ })
31
+ }
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ nodes
38
+ end
39
+
40
+ def params
41
+ @props_wrapper
42
+ end
43
+
44
+ def props
45
+ Hash.new(`#{@native}.props`)
46
+ end
47
+
48
+ def refs
49
+ Hash.new(`#{@native}.refs`)
50
+ end
51
+
52
+ def state
53
+ @state_wrapper ||= StateWrapper.new(@native, self)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -1,5 +1,11 @@
1
1
  module React
2
2
  module Component
3
+
4
+ def deprecated_params_method(name, *args, &block)
5
+ React::Component.deprecation_warning"Direct access to param `#{name}`. Use `params.#{name}` instead."
6
+ params.send(name, *args, &block)
7
+ end
8
+
3
9
  class PropsWrapper
4
10
  attr_reader :props
5
11
 
@@ -0,0 +1,96 @@
1
+ module React
2
+ module Component
3
+ # contains the name of all HTML tags, and the mechanism to register a component
4
+ # class as a new tag
5
+ module Tags
6
+ HTML_TAGS = %w(a abbr address area article aside audio b base bdi bdo big blockquote body br
7
+ button canvas caption cite code col colgroup data datalist dd del details dfn
8
+ dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5
9
+ h6 head header hr html i iframe img input ins kbd keygen label legend li link
10
+ main map mark menu menuitem meta meter nav noscript object ol optgroup option
11
+ output p param picture pre progress q rp rt ruby s samp script section select
12
+ small source span strong style sub summary sup table tbody td textarea tfoot th
13
+ thead time title tr track u ul var video wbr)
14
+
15
+ # note: any tag can end in _as_node but this is deprecated
16
+
17
+ # the present method is retained as a legacy behavior
18
+
19
+ def present(component, *params, &children)
20
+ React::RenderingContext.render(component, *params, &children)
21
+ end
22
+
23
+ def present_as_node(component, *params, &children)
24
+ React::RenderingContext.build_only(component, *params, &children)
25
+ end
26
+
27
+ # define each predefined tag as an instance method
28
+
29
+ HTML_TAGS.each do |tag|
30
+ define_method(tag) do |*params, &children|
31
+ React::RenderingContext.render(tag, *params, &children)
32
+ end
33
+ alias_method tag.upcase, tag
34
+ const_set tag.upcase, tag
35
+ # handle deprecated _as_node style
36
+ define_method("#{tag}_as_node") do |*params, &children|
37
+ React::RenderingContext.build_only(tag, *params, &children)
38
+ end
39
+ end
40
+
41
+ # use method_missing to look up component names in the form of "Foo(..)"
42
+ # where there is no preceeding scope.
43
+
44
+ def method_missing(name, *params, &children)
45
+ if name =~ /_as_node$/
46
+ # handle deprecated _as_node style
47
+ component = find_component(name.gsub(/_as_node$/, ''))
48
+ return React::RenderingContext.build_only(component, *params, &children) if component
49
+ else
50
+ component = find_component(name)
51
+ return React::RenderingContext.render(component, *params, &children) if component
52
+ end
53
+ Object.method_missing(name, *params, &children)
54
+ end
55
+
56
+ # install methods with the same name as the component in the parent class/module
57
+ # thus component names in the form Foo::Bar(...) will work
58
+
59
+ class << self
60
+ def included(component)
61
+ _name, parent = find_name_and_parent(component)
62
+ class << parent
63
+ define_method _name do |*params, &children|
64
+ React::RenderingContext.render(component, *params, &children)
65
+ end
66
+ # handle deprecated _as_node style
67
+ define_method "#{_name}_as_node" do |*params, &children|
68
+ React::RenderingContext.build_only(component, *params, &children)
69
+ end
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+ def find_name_and_parent(component)
76
+ split_name = component.name && component.name.split('::')
77
+ if split_name && split_name.length > 1
78
+ [split_name.last, split_name.inject([Module]) { |a, e| a + [a.last.const_get(e)] }[-2]]
79
+ end
80
+ end
81
+ end
82
+
83
+ private
84
+
85
+ def find_component(name)
86
+ scopes = self.class.name.split('::').inject([Module]) do |nesting, next_const|
87
+ nesting + [nesting.last.const_get(next_const)]
88
+ end.reverse
89
+ scope = scopes.detect { |s| s.const_defined?(name) } || return
90
+ component = scope.const_get(name)
91
+ return component if component.method_defined?(:render)
92
+ raise "#{name} does not appear to be a react component."
93
+ end
94
+ end
95
+ end
96
+ end
@@ -1,53 +1,90 @@
1
1
  module React
2
- class NativeLibrary
3
- def self.renames_and_exclusions
4
- @renames_and_exclusions ||= {}
5
- end
2
+ # NativeLibrary handles importing JS libraries. Importing native components is handled
3
+ # by the React::Base. It also provides several methods used by auto-import.rb
6
4
 
7
- def self.libraries
8
- @libraries ||= []
9
- end
5
+ # A NativeLibrary is simply a wrapper that holds the name of the native js library.
6
+ # It responds to const_missing and method_missing by looking up objects within the js library.
7
+ # If the object is a react component it is wrapped by a reactrb component class, otherwise
8
+ # a nested NativeLibrary is returned.
10
9
 
11
- def self.const_missing(name)
12
- if renames_and_exclusions.has_key? name
13
- if native_name = renames_and_exclusions[name]
14
- native_name
15
- else
16
- super
17
- end
18
- else
19
- libraries.each do |library|
20
- native_name = "#{library}.#{name}"
21
- native_component = `eval(#{native_name})` rescue nil
22
- React::API.import_native_component(name, native_component) and return name if native_component and `native_component != undefined`
10
+ # Two macros are provided: imports (for naming the native library) and renames which allows
11
+ # the members of a library to be given different names within the ruby name space.
12
+
13
+ # Public methods used by auto-import.rb are import_const_from_native and find_and_render_component
14
+ class NativeLibrary
15
+ class << self
16
+ def imports(native_name)
17
+ @native_prefix = "#{native_name}."
18
+ self
19
+ end
20
+
21
+ def rename(rename_list)
22
+ # rename_list is a hash in the form: native_name => ruby_name, native_name => ruby_name
23
+ rename_list.each do |js_name, ruby_name|
24
+ native_name = lookup_native_name(js_name)
25
+ if lookup_native_name(js_name)
26
+ create_component_wrapper(self, native_name, ruby_name) ||
27
+ create_library_wrapper(self, native_name, ruby_name)
28
+ else
29
+ raise "class #{name} < React::NativeLibrary could not import #{js_name}. "\
30
+ "Native value #{scope_native_name(js_name)} is undefined."
31
+ end
23
32
  end
24
- name
25
33
  end
26
- end
27
34
 
28
- def self.method_missing(n, *args, &block)
29
- name = n
30
- if name =~ /_as_node$/
31
- node_only = true
32
- name = name.gsub(/_as_node$/, "")
35
+ def import_const_from_native(klass, const_name, create_library)
36
+ native_name = lookup_native_name(const_name) ||
37
+ lookup_native_name(const_name[0].downcase + const_name[1..-1])
38
+ native_name && (
39
+ create_component_wrapper(klass, native_name, const_name) || (
40
+ create_library &&
41
+ create_library_wrapper(klass, native_name, const_name)))
33
42
  end
34
- unless name = const_get(name)
35
- return super
43
+
44
+ def const_missing(const_name)
45
+ import_const_from_native(self, const_name, true) || super
36
46
  end
37
- React::RenderingContext.build_or_render(node_only, name, *args, &block)
38
- rescue
39
- end
40
47
 
41
- def self.imports(library)
42
- libraries << library
43
- end
48
+ def method_missing(method_name, *args, &block)
49
+ method = method_name.gsub(/_as_node$/, '') # remove once _as_node is deprecated.
50
+ component_class = get_const(method) if const_defined?(method)
51
+ component_class ||= import_const_from_native(self, method, false)
52
+ raise 'could not import a react component named: '\
53
+ "#{scope_native_name method}" unless component_class
54
+ if method == method_name
55
+ React::RenderingContext.render(component_class, *args, &block)
56
+ else # remove once _as_node is deprecated.
57
+ React::RenderingContext.build_only(component_class, *args, &block)
58
+ end
59
+ end
44
60
 
45
- def self.rename(rename_list={})
46
- renames_and_exclusions.merge!(rename_list.invert)
47
- end
61
+ private
48
62
 
49
- def self.exclude(*exclude_list)
50
- renames_and_exclusions.merge(Hash[exclude_list.map {|k| [k, nil]}])
63
+ def lookup_native_name(js_name)
64
+ native_name = scope_native_name(js_name)
65
+ `eval(#{native_name}) !== undefined && native_name`
66
+ rescue
67
+ nil
68
+ end
69
+
70
+ def scope_native_name(js_name)
71
+ "#{@native_prefix}#{js_name}"
72
+ end
73
+
74
+ def create_component_wrapper(klass, native_name, ruby_name)
75
+ if React::API.native_react_component?(native_name)
76
+ new_klass = klass.const_set ruby_name, Class.new
77
+ new_klass.class_eval do
78
+ include React::Component
79
+ imports native_name
80
+ end
81
+ new_klass
82
+ end
83
+ end
84
+
85
+ def create_library_wrapper(klass, native_name, ruby_name)
86
+ klass.const_set ruby_name, Class.new(React::NativeLibrary).imports(native_name)
87
+ end
51
88
  end
52
89
  end
53
90
  end
@@ -4,12 +4,11 @@ module React
4
4
  attr_accessor :waiting_on_resources
5
5
  end
6
6
 
7
- def self.build_or_render(node_only, name, *args, &block)
8
- if node_only
9
- React::RenderingContext.build { React::RenderingContext.render(name, *args, &block) }.to_n
10
- else
11
- React::RenderingContext.render(name, *args, &block)
12
- end
7
+ def self.build_only(name, *args, &block)
8
+ React::Component.deprecation_warning(
9
+ '..._as_node is deprecated. Render component and then use the .node method instead'
10
+ )
11
+ React::RenderingContext.build { React::RenderingContext.render(name, *args, &block) }.to_n
13
12
  end
14
13
 
15
14
  def self.render(name, *args, &block)
@@ -55,15 +54,12 @@ module React
55
54
  element
56
55
  end
57
56
 
58
- def self.build(&block)
57
+ def self.build
59
58
  current = @buffer
60
59
  @buffer = []
61
60
  return_val = yield @buffer
62
61
  @buffer = current
63
62
  return_val
64
- #ensure
65
- # @buffer = current
66
- # return_val
67
63
  end
68
64
 
69
65
  def self.as_node(element)
@@ -71,7 +67,7 @@ module React
71
67
  element
72
68
  end
73
69
 
74
- class << self; alias_method :delete, :as_node; end
70
+ class << self; alias delete as_node; end
75
71
 
76
72
  def self.replace(e1, e2)
77
73
  @buffer[@buffer.index(e1)] = e2
@@ -85,24 +81,26 @@ module React
85
81
  end
86
82
 
87
83
  class ::Object
88
-
89
- ["span", "td", "th", "while_loading"].each do |tag|
90
- define_method(tag) do | *args, &block |
84
+ [:span, :td, :th, :while_loading].each do |tag|
85
+ define_method(tag) do |*args, &block|
91
86
  args.unshift(tag)
92
- return self.method_missing(*args, &block) if self.is_a? React::Component
93
- React::RenderingContext.render(*args) { self.to_s }
87
+ return send(*args, &block) if is_a? React::Component
88
+ React::RenderingContext.render(*args) { to_s }
94
89
  end
95
90
  end
96
91
 
97
92
  def para(*args, &block)
98
- args.unshift("p")
99
- return self.method_missing(*args, &block) if self.is_a? React::Component
100
- React::RenderingContext.render(*args) { self.to_s }
93
+ args.unshift(:p)
94
+ return send(*args, &block) if is_a? React::Component
95
+ React::RenderingContext.render(*args) { to_s }
101
96
  end
102
97
 
103
98
  def br
104
- return self.method_missing(*["br"]) if self.is_a? React::Component
105
- React::RenderingContext.render("span") { React::RenderingContext.render(self.to_s); React::RenderingContext.render("br") }
99
+ return send(:br) if is_a? React::Component
100
+ React::RenderingContext.render(:span) do
101
+ React::RenderingContext.render(to_s)
102
+ React::RenderingContext.render(:br)
103
+ end
106
104
  end
107
105
  end
108
106
  end
@@ -3,25 +3,20 @@ require 'active_support'
3
3
  require 'react/component/base'
4
4
 
5
5
  module React
6
- HTML_TAGS = %w(a abbr address area article aside audio b base bdi bdo big blockquote body br
7
- button canvas caption cite code col colgroup data datalist dd del details dfn
8
- dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5
9
- h6 head header hr html i iframe img input ins kbd keygen label legend li link
10
- main map mark menu menuitem meta meter nav noscript object ol optgroup option
11
- output p param picture pre progress q rp rt ruby s samp script section select
12
- small source span strong style sub summary sup table tbody td textarea tfoot th
13
- thead time title tr track u ul var video wbr)
6
+
14
7
  ATTRIBUTES = %w(accept acceptCharset accessKey action allowFullScreen allowTransparency alt
15
- async autoComplete autoPlay cellPadding cellSpacing charSet checked classID
16
- className cols colSpan content contentEditable contextMenu controls coords
17
- crossOrigin data dateTime defer dir disabled download draggable encType form
18
- formAction formEncType formMethod formNoValidate formTarget frameBorder height
19
- hidden href hrefLang htmlFor httpEquiv icon id label lang list loop manifest
20
- marginHeight marginWidth max maxLength media mediaGroup method min multiple
21
- muted name noValidate open pattern placeholder poster preload radioGroup
22
- readOnly rel required role rows rowSpan sandbox scope scrolling seamless
23
- selected shape size sizes span spellCheck src srcDoc srcSet start step style
24
- tabIndex target title type useMap value width wmode dangerouslySetInnerHTML)
8
+ async autoComplete autoPlay cellPadding cellSpacing charSet checked classID
9
+ className cols colSpan content contentEditable contextMenu controls coords
10
+ crossOrigin data dateTime defer dir disabled download draggable encType form
11
+ formAction formEncType formMethod formNoValidate formTarget frameBorder height
12
+ hidden href hrefLang htmlFor httpEquiv icon id label lang list loop manifest
13
+ marginHeight marginWidth max maxLength media mediaGroup method min multiple
14
+ muted name noValidate open pattern placeholder poster preload radioGroup
15
+ readOnly rel required role rows rowSpan sandbox scope scrolling seamless
16
+ selected shape size sizes span spellCheck src srcDoc srcSet start step style
17
+ tabIndex target title type useMap value width wmode dangerouslySetInnerHTML)
18
+
19
+ HASH_ATTRIBUTES = %w(data aria)
25
20
 
26
21
  def self.create_element(type, properties = {}, &block)
27
22
  React::API.create_element(type, properties, &block)
@@ -78,11 +73,6 @@ module React
78
73
  end
79
74
 
80
75
  Element.instance_eval do
81
- class Element
82
- class DummyContext < React::Component::Base
83
- end
84
- end
85
-
86
76
  def self.find(selector)
87
77
  selector = begin
88
78
  selector.dom_node
@@ -96,11 +86,11 @@ Element.instance_eval do
96
86
  find(selector)
97
87
  end
98
88
 
99
- define_method :render do |&block|
100
- React.render(
101
- React::RenderingContext.render(nil) do
102
- ::Element::DummyContext.new.instance_eval(&block)
103
- end, self
104
- )
89
+ define_method :render do |container = nil, params = {}, &block|
90
+ klass = Class.new(React::Component::Base)
91
+ klass.class_eval do
92
+ render(container, params, &block)
93
+ end
94
+ React.render(React.create_element(klass), self)
105
95
  end
106
96
  end if Object.const_defined?('Element')
@@ -10,7 +10,9 @@ module ReactiveRuby
10
10
  def react_component(name, props = {}, options = {}, &block)
11
11
  options = context_initializer_options(options, name) if options[:prerender]
12
12
  props = serialized_props(props, name, controller)
13
- super(top_level_name, props, options, &block) + footers
13
+ super(top_level_name, props, options, &block).gsub("\n","")
14
+ .gsub(/(<script>.*<\/script>)<\/div>$/,'</div>\1').html_safe +
15
+ footers
14
16
  end
15
17
 
16
18
  private