yoga_layout 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 26a638d33929146562ee6e51da0f722c69e6396b
4
+ data.tar.gz: 599d1368d1dbc2a113ecbd12492fdcb0bac63c10
5
+ SHA512:
6
+ metadata.gz: ce2a19b0ec43b55d2c541352c6e61f1f1db096b60b106f35f477e08697d1f1d4c294f2a9b2ff49ce86bd067d870e4ffe240885afde25a48fa60a909cb9531e82
7
+ data.tar.gz: 25f13f5bcf4d48277ecfe898795a54f208ef5ef8a6708c2b018b1f484a11c3e243ef41f084334cde58503b55763871c98463cb4e3bde250ef71c724dd3c3818a
@@ -0,0 +1,22 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+
16
+ # rspec failure tracking
17
+ .rspec_status
18
+
19
+ # we don't care about the Yoga source files right now; they should be copied in
20
+ # during gem build from the repo root
21
+ ext/yoga_layout/*.c
22
+ ext/yoga_layout/*.h
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.0.0
5
+ before_install: gem install bundler -v 1.15.2
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in yoga_layout.gemspec
6
+ gemspec
@@ -0,0 +1,35 @@
1
+ # YogaLayout
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/yoga_layout`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'yoga_layout'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install yoga_layout
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/justjake/yoga_layout.
@@ -0,0 +1,176 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ require "rake/extensiontask"
7
+
8
+ task :build => :compile
9
+
10
+ Rake::ExtensionTask.new("yoga_layout") do |ext|
11
+ ext.lib_dir = "lib/yoga_layout"
12
+ end
13
+
14
+ task :copy_src do
15
+ sh 'cp ../yoga/* ext/yoga_layout'
16
+ end
17
+
18
+ # Parses Yoga.h into ruby function information
19
+ class YogaHeaderParser
20
+ # partial regexes for the parts of a macro call
21
+ MACRO_NAME = 'YG_[A-Z_]+'
22
+ ARGUMENT = '[*\w ]+'
23
+ COMMA = ',\s?'
24
+
25
+ # a regex to parse a single macro call
26
+ MACRO_REGEX = /
27
+ ^ # start of line
28
+ (?<macro>#{MACRO_NAME}) # eg, 'YG_NODE_STYLE_PROPERTY'
29
+ \( # '('
30
+ (?<type>#{ARGUMENT}) # the "type" argument, eg 'YGValue' or 'void *'
31
+ #{COMMA} #
32
+ (?<name>#{ARGUMENT}) # the name of the property, eg 'MinWidth'
33
+ (?: # optional group, because not all calls have a paramName
34
+ #{COMMA}
35
+ (?<paramName>#{ARGUMENT}) # the paramName, eg 'minWidth'
36
+ )? # close the optional group, and mark it optional
37
+ \) # ')'
38
+ ;? # usually, but not always, we need a ; at the end
39
+ $ # end of line
40
+ /x
41
+
42
+ def initialize(header_source)
43
+ @header = header_source
44
+ @functions = []
45
+ end
46
+
47
+ def call
48
+ matches.each do |match|
49
+ handle_match(match)
50
+ end
51
+ @functions
52
+ end
53
+
54
+ # crazy ruby nonsense to get all the matches of the regex on the string
55
+ def matches
56
+ @matches ||= @header.to_enum(:scan, MACRO_REGEX).map { Regexp.last_match }
57
+ end
58
+
59
+ def handle_match(match)
60
+ case match['macro']
61
+ when 'YG_NODE_PROPERTY'
62
+ yg_node_property(match)
63
+ when 'YG_NODE_STYLE_PROPERTY'
64
+ yg_node_style_property(match)
65
+ when 'YG_NODE_STYLE_PROPERTY_UNIT'
66
+ yg_node_style_property_unit(match)
67
+ when 'YG_NODE_STYLE_PROPERTY_UNIT_AUTO'
68
+ yg_node_style_property_unit_auto(match)
69
+ when 'YG_NODE_STYLE_EDGE_PROPERTY'
70
+ yg_node_style_edge_property(match)
71
+ when 'YG_NODE_STYLE_EDGE_PROPERTY_UNIT'
72
+ yg_node_style_edge_property_unit(match)
73
+ when 'YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO'
74
+ yg_node_style_edge_property_unit_auto(match)
75
+ when 'YG_NODE_LAYOUT_PROPERTY'
76
+ yg_node_layout_property(match)
77
+ when 'YG_NODE_LAYOUT_EDGE_PROPERTY'
78
+ yg_node_layout_edge_property(match)
79
+ else
80
+ raise "Unparsable: #{match}"
81
+ end
82
+ end
83
+
84
+ def declare(fn_info)
85
+ name, args, result = fn_info
86
+ name = name.to_sym
87
+ args = args.map { |t| normalize_type(t) }
88
+ result = normalize_type(result)
89
+ @functions << [name, args, result]
90
+ end
91
+
92
+ def normalize_type(type)
93
+ case type
94
+ when 'void *'
95
+ :pointer
96
+ when Symbol
97
+ type
98
+ when String
99
+ type.to_sym
100
+ else
101
+ raise "cannot normalize type #{type.inpect}"
102
+ end
103
+ end
104
+
105
+ def yg_node_property(match)
106
+ declare ["YGNodeSet#{match['name']}", [:YGNodeRef, match['type']], :void]
107
+ declare ["YGNodeGet#{match['name']}", [:YGNodeRef], match['type']]
108
+ end
109
+
110
+ def yg_node_style_property(match)
111
+ declare ["YGNodeStyleSet#{match['name']}", [:YGNodeRef, match['type']], :void]
112
+ declare ["YGNodeStyleGet#{match['name']}", [:YGNodeRef], match['type']]
113
+ end
114
+
115
+ def yg_node_style_property_unit(match)
116
+ declare ["YGNodeStyleSet#{match['name']}", [:YGNodeRef, :float], :void]
117
+ declare ["YGNodeStyleSet#{match['name']}Percent", [:YGNodeRef, :float], :void]
118
+ declare ["YGNodeStyleGet#{match['name']}", [:YGNodeRef], match['type']]
119
+ end
120
+
121
+ def yg_node_style_property_unit_auto(match)
122
+ puts "unit_auto: #{match.inspect}"
123
+ yg_node_style_property_unit(match)
124
+ declare ["YGNodeStyleSet#{match['name']}Auto", [:YGNodeRef], :void]
125
+ end
126
+
127
+ def yg_node_style_edge_property(match)
128
+ declare ["YGNodeStyleSet#{match['name']}", [:YGNodeRef, :YGEdge, match['type']], :void]
129
+ declare ["YGNodeStyleGet#{match['name']}", [:YGNodeRef, :YGEdge], match['type']]
130
+ end
131
+
132
+ def yg_node_style_edge_property_unit(match)
133
+ declare ["YGNodeStyleSet#{match['name']}", [:YGNodeRef, :YGEdge, :float], :void]
134
+ declare ["YGNodeStyleSet#{match['name']}Percent", [:YGNodeRef, :YGEdge, :float], :void]
135
+ # According to YGMacros.h, the return type here should be
136
+ # pointerOf(match['type']) on Windows ARM.
137
+ # This is Ruby, we don't care.
138
+ declare ["YGNodeStyleGet#{match['name']}", [:YGNodeRef, :YGEdge], match['type']]
139
+ end
140
+
141
+ def yg_node_style_edge_property_unit_auto(match)
142
+ declare ["YGNodeStyleSet#{match['name']}Auto", [:YGNodeRef, :YGEdge], :void]
143
+ end
144
+
145
+ def yg_node_layout_property(match)
146
+ declare ["YGNodeLayoutGet#{match['name']}", [:YGNodeRef], match['type']]
147
+ end
148
+
149
+ def yg_node_layout_edge_property(match)
150
+ declare ["YGNodeLayoutGet#{match['name']}", [:YGNodeRef, :YGEdge], match['type']]
151
+ end
152
+ end
153
+
154
+ desc 'Auto-generate lib/yoga_layout/native/functions.rb from Yoga.h by parsing macros'
155
+ task :ygnode_properties do
156
+ header = File.read('../yoga/Yoga.h')
157
+
158
+ parser = YogaHeaderParser.new(header)
159
+ functions = parser.call
160
+
161
+ File.open('lib/yoga_layout/bindings/ygnode_properties.rb', 'w') do |file|
162
+ file.puts('# Auto-generated by Rake from Yoga.h')
163
+ file.puts('# Do not edit by hand')
164
+ file.puts("module YogaLayout")
165
+ file.puts(" module Bindings")
166
+ functions.each do |fn_info|
167
+ attrs = fn_info.inspect[1..-2]
168
+ puts "writing function #{attrs}"
169
+ file.puts(" remember_function #{attrs}")
170
+ end
171
+ file.puts(" end")
172
+ file.puts("end")
173
+ end
174
+ end
175
+
176
+ task :default => [:copy_src, :ygnode_properties, :clobber, :compile, :spec]
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "yoga_layout"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ require "pry"
10
+ Pry.start
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require 'pry'
5
+ require "yoga_layout"
6
+ require "drawille"
7
+
8
+ # You can add fixtures and/or initialization code here to make experimenting
9
+ # with your gem easier. You can also use a different console, if you like.
10
+
11
+ def node_enum(node)
12
+ Enumerator.new do |y|
13
+ queue = []
14
+ queue << node
15
+
16
+ while queue.size > 0
17
+ node = queue.pop
18
+ y << node
19
+ node.get_child_count.times do |i|
20
+ child = node.get_child(i)
21
+ queue << child
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ def rect(brush, top, left, width, height)
28
+ top_left = [left, top]
29
+ top_right = [left + width, top]
30
+ bottom_right = [left + width, top + height]
31
+ bottom_left = [left, top + height]
32
+
33
+ brush.line(from: top_left, to: top_right)
34
+ brush.line(from: top_right, to: bottom_right)
35
+ brush.line(from: bottom_right, to: bottom_left)
36
+ brush.line(from: bottom_left, to: top_left)
37
+ end
38
+
39
+ def show_layout(root)
40
+ root.calculate_layout
41
+ canvas = Drawille::Canvas.new
42
+ brush = Drawille::Brush.new(canvas)
43
+ node_enum(root).each do |node|
44
+ rect(
45
+ brush,
46
+ node.layout[:top],
47
+ node.layout[:left],
48
+ node.layout[:width],
49
+ node.layout[:height],
50
+ )
51
+ end
52
+ puts canvas.frame
53
+ end
54
+
55
+ class Draw
56
+ def initialize
57
+ @canvas = Drawille::Canvas.new
58
+ @brush = Drawille::Brush.new(@canvas)
59
+ end
60
+
61
+ def draw_node(node)
62
+ end
63
+
64
+ def show
65
+ puts @canvas.frame
66
+ end
67
+ end
68
+
69
+ layout = YogaLayout::Node[
70
+ width: 500,
71
+ height: 100,
72
+ flex_direction: :row,
73
+ padding: 20,
74
+ children: [
75
+ YogaLayout::Node[
76
+ width: 80,
77
+ margin_end: 20,
78
+ ],
79
+ YogaLayout::Node[
80
+ height: 25,
81
+ align_self: :center,
82
+ flex_grow: 1,
83
+ ]
84
+ ],
85
+ ]
86
+
87
+ binding.pry
88
+
89
+ show_layout(layout)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,3 @@
1
+ require "mkmf"
2
+
3
+ create_makefile("yoga_layout/yoga_layout")
@@ -0,0 +1,33 @@
1
+ # YogaLayout provides a thin FFI-based wrapper around the core Yoga library.
2
+ #
3
+ # Yoga is a cross-platform layout engine enabling maximum collaboration within
4
+ # your team by implementing an API familiar to many designers and opening it up
5
+ # to developers across different platforms.
6
+ #
7
+ # @see https://facebook.github.io/yoga
8
+ module YogaLayout
9
+ # Root error class for the YogaLayout module
10
+ class Error < ::StandardError; end
11
+
12
+ # Turn a CamelCase string into a snake_case string.
13
+ #
14
+ # @api private
15
+ def self.underscore(string)
16
+ string.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
17
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
18
+ downcase
19
+ end
20
+
21
+ require 'yoga_layout/version'
22
+ require 'yoga_layout/bindings'
23
+ require 'yoga_layout/node'
24
+ require 'yoga_layout/config'
25
+
26
+ def self.undefined
27
+ ::Float::NAN
28
+ end
29
+
30
+ def self.float_is_undefined?(float)
31
+ ::YogaLayout::Bindings.YGFloatIsUndefined(float)
32
+ end
33
+ end
@@ -0,0 +1,39 @@
1
+ require 'ffi'
2
+
3
+ # Our C extension, which loads the Yoga C code.
4
+ require "yoga_layout/yoga_layout"
5
+
6
+ module YogaLayout
7
+ # Native is the libffi wrapper around Yoga.
8
+ # It does not implement anything novel like memory management or nice ruby types.
9
+ # It's just a compatibility layer.
10
+ module Bindings
11
+ extend ::FFI::Library
12
+ # ref https://github.com/ffi/ffi/wiki/Loading-Libraries#in-memory-libraries
13
+ ffi_lib ::FFI::USE_THIS_PROCESS_AS_LIBRARY
14
+
15
+ def self.functions
16
+ @functions ||= {}
17
+ end
18
+
19
+ # Wrapper around FFI::Library.attach_function that also remembers the function
20
+ # name and arguments for later static analysis
21
+ def self.remember_function(*args)
22
+ result = attach_function(*args)
23
+ functions[args.first] = args
24
+ result
25
+ end
26
+
27
+ # Auto-genrated by ../../enums.py
28
+ require 'yoga_layout/bindings/enums'
29
+
30
+ # Written by hand
31
+ require 'yoga_layout/bindings/typedefs'
32
+ require 'yoga_layout/bindings/ygnode'
33
+ require 'yoga_layout/bindings/ygconfig'
34
+ require 'yoga_layout/bindings/misc'
35
+
36
+ # Auto-generated by `rake ygnode_properties`
37
+ require 'yoga_layout/bindings/ygnode_properties'
38
+ end
39
+ end