yoga_layout 0.0.1

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,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