reactrb 0.8.3 → 0.8.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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