stylegen 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5882aa3fdd2e17f9e0fe683c07fd07d5c045f505a78a8ba7c5765edfc60a2c6e
4
+ data.tar.gz: f583e4f26b3e4dccc121eceec5a7f5e4349f7210e660527aa07128f1401e2837
5
+ SHA512:
6
+ metadata.gz: d525975a51b7415c727b1f46299ec37283bcc2d2efbde3450cc361c4095c27abc7d2d606863676acc8f35950dbe885519cf1568fab89520fb731cf92812445d0
7
+ data.tar.gz: 6aa2ac484c0697175a7f6e1ebf94221fcbf66f78e2ba11d3e351434c1949646bc3ff49e46ccf9895703327217a33e1c766d5eb9c3df1f9589b92f210ded81395
@@ -0,0 +1,32 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ test:
11
+
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ matrix:
15
+ ruby-version:
16
+ - "2.5"
17
+ - "2.6"
18
+ - "2.7"
19
+ - "3.0"
20
+
21
+ steps:
22
+ - uses: actions/checkout@v2
23
+ - name: Set up Ruby
24
+ # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
25
+ # change this to (see https://github.com/ruby/setup-ruby#versioning):
26
+ # uses: ruby/setup-ruby@v1
27
+ uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
28
+ with:
29
+ ruby-version: ${{ matrix.ruby-version }}
30
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
31
+ - name: Run tests
32
+ run: bundle exec rake
@@ -0,0 +1,2 @@
1
+ .idea
2
+ pkg
@@ -0,0 +1,33 @@
1
+ require:
2
+ - rubocop-rake
3
+ - rubocop-minitest
4
+
5
+ AllCops:
6
+ TargetRubyVersion: 2.4
7
+ NewCops: enable
8
+
9
+ Style/StringLiterals:
10
+ Enabled: true
11
+ EnforcedStyle: double_quotes
12
+
13
+ Metrics/ClassLength:
14
+ Enabled: true
15
+ Max: 150
16
+
17
+ Naming/MethodParameterName:
18
+ Enabled: false
19
+
20
+ Metrics/MethodLength:
21
+ Enabled: false
22
+
23
+ Metrics/AbcSize:
24
+ Enabled: false
25
+
26
+ Style/Documentation:
27
+ Enabled: false
28
+
29
+ Style/ParallelAssignment:
30
+ Enabled: false
31
+
32
+ Minitest/AssertInDelta:
33
+ Enabled: false
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec
@@ -0,0 +1,61 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ stylegen (0.1.0)
5
+ dry-inflector (>= 0.2.0)
6
+ json_schemer (>= 0.2.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ ast (2.4.1)
12
+ dry-inflector (0.2.0)
13
+ ecma-re-validator (0.3.0)
14
+ regexp_parser (~> 2.0)
15
+ hana (1.3.7)
16
+ json_schemer (0.2.17)
17
+ ecma-re-validator (~> 0.3)
18
+ hana (~> 1.3)
19
+ regexp_parser (~> 2.0)
20
+ uri_template (~> 0.7)
21
+ minitest (5.14.3)
22
+ parallel (1.20.1)
23
+ parser (3.0.0.0)
24
+ ast (~> 2.4.1)
25
+ rainbow (3.0.0)
26
+ rake (13.0.3)
27
+ regexp_parser (2.0.3)
28
+ rexml (3.2.4)
29
+ rubocop (1.8.1)
30
+ parallel (~> 1.10)
31
+ parser (>= 3.0.0.0)
32
+ rainbow (>= 2.2.2, < 4.0)
33
+ regexp_parser (>= 1.8, < 3.0)
34
+ rexml
35
+ rubocop-ast (>= 1.2.0, < 2.0)
36
+ ruby-progressbar (~> 1.7)
37
+ unicode-display_width (>= 1.4.0, < 3.0)
38
+ rubocop-ast (1.4.0)
39
+ parser (>= 2.7.1.5)
40
+ rubocop-minitest (0.10.3)
41
+ rubocop (>= 0.87, < 2.0)
42
+ rubocop-rake (0.5.1)
43
+ rubocop
44
+ ruby-progressbar (1.11.0)
45
+ unicode-display_width (2.0.0)
46
+ uri_template (0.7.0)
47
+
48
+ PLATFORMS
49
+ ruby
50
+
51
+ DEPENDENCIES
52
+ bundler
53
+ minitest (>= 5.14.0)
54
+ rake
55
+ rubocop
56
+ rubocop-minitest
57
+ rubocop-rake
58
+ stylegen!
59
+
60
+ BUNDLED WITH
61
+ 2.1.4
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2021 Ramon Torres
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -0,0 +1,97 @@
1
+ # stylegen
2
+
3
+ A CLI utility that allows managing the colors used in an iOS app from a centralized YAML file in a type-safe way.
4
+
5
+ ![CI](https://github.com/raymondjavaxx/stylegen/workflows/CI/badge.svg?branch=master)
6
+
7
+ ## Installing
8
+
9
+ You can install `stylegen` manually by running:
10
+
11
+ ```shell
12
+ $ gem install stylegen
13
+ ```
14
+
15
+ Or by adding the following entry to your [Gemfile](https://guides.cocoapods.org/using/a-gemfile.html), then running `$ bundle install`.
16
+
17
+ ```ruby
18
+ gem "stylegen"
19
+ ```
20
+
21
+ ## How to use
22
+
23
+ Create a `theme.yaml` file in the root of your project. You can use the following YAML file as a starting point:
24
+
25
+ ```yaml
26
+ # Name of the design system. Defaults to "Theme".
27
+ # Feel free to use your company name, name of product,
28
+ # or name of your design system.
29
+ # e.g.: Primer, Material, Polaris, etc.
30
+ system_name: "Theme"
31
+
32
+ # Path of generated Swift file.
33
+ output_path: "Colors.swift"
34
+
35
+ # Key-value pairs of theme colors.
36
+ colors:
37
+
38
+ accent: # Keys will be used as color names.
39
+ color: "#00BFC2" # Hex color
40
+
41
+ # Shorthand syntax
42
+ warning: "#ED4337"
43
+
44
+ text_primary:
45
+ light: # Value for light mode
46
+ color: "#000000"
47
+ # Optionally you can specify an alpha value.
48
+ # Defaults to `1.0`.
49
+ alpha: 0.95
50
+ dark: # Value for dark mode
51
+ color: "#FFFFFF"
52
+
53
+ text_secondary:
54
+ light:
55
+ color: "#000000"
56
+ alpha: 0.4
57
+ dark:
58
+ color: "#FFFFFF"
59
+ alpha: 0.6
60
+
61
+ primary_background:
62
+ light: "#FFFFFF"
63
+ dark:
64
+ # Value for base (non-elevated) level
65
+ base: "#0D0D0D"
66
+ # Value for elevated level
67
+ elevated: "#191D1D"
68
+ ```
69
+
70
+ After creating the theme file run:
71
+
72
+ ```shell
73
+ $ stylegen
74
+ ```
75
+
76
+ This will generate a Swift file that you can add to your target. The generated file will contain all the colors and utility methods for referencing the colors.
77
+
78
+ In places where you normally do:
79
+
80
+ ```swift
81
+ self.backgroundColor = UIColor(named: "AccentColor")
82
+ ```
83
+
84
+ Now you can just do:
85
+
86
+ ```swift
87
+ self.backgroundColor = .theme(.accent)
88
+ ```
89
+
90
+ The `.theme()` static method serves as a namespace to easily distinguish between UIKit's built-in colors and our custom colors. The name of the namespacing function is inferred from the `system_name` property in the YAML file.
91
+
92
+ ## TODO
93
+
94
+ * `$ stylegen init` command
95
+ * Option to specify target frameworks: AppKit, UIKit, Core Graphics, and SwiftUI
96
+ * SwiftUI support
97
+ * AppKit support
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new
7
+
8
+ task default: :test
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "yaml"
5
+ require "optparse"
6
+ require "stylegen"
7
+
8
+ @options = {}
9
+
10
+ OptionParser.new do |opts|
11
+ opts.on_tail("--version", "Show version") do
12
+ puts Stylegen::VERSION
13
+ exit
14
+ end
15
+ end.parse!
16
+
17
+ data = File.open("theme.yaml") { |file| YAML.safe_load(file) }
18
+
19
+ validator = Stylegen::Validator.new
20
+ unless validator.valid?(data)
21
+ warn "theme.yaml contains one or more errors:"
22
+
23
+ validator.validate(data).each do |e|
24
+ warn " #{e}"
25
+ end
26
+
27
+ exit(1)
28
+ end
29
+
30
+ generator = Stylegen::Generator.new(data)
31
+ generator.generate
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stylegen/version"
4
+ require "stylegen/colors"
5
+ require "stylegen/generator"
6
+ require "stylegen/data"
7
+ require "stylegen/validator"
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stylegen/colors/color"
4
+ require "stylegen/colors/light_dark_color"
5
+ require "stylegen/colors/base_elevated_color"
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stylegen
4
+ class BaseElevatedColor
5
+ def initialize(base, elevated)
6
+ @base, @elevated = base, elevated
7
+ end
8
+
9
+ def to_s(struct_name, indent = 0)
10
+ indent_prefix = " " * indent
11
+
12
+ result = []
13
+ result << "#{struct_name}("
14
+ result << "#{indent_prefix} base: #{@base.to_s(struct_name, indent + 4)},"
15
+ result << "#{indent_prefix} elevated: #{@elevated.to_s(struct_name, indent + 4)}"
16
+ result << "#{indent_prefix})"
17
+
18
+ result.join("\n")
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stylegen
4
+ class Color
5
+ attr_reader :red, :green, :blue, :alpha
6
+
7
+ def initialize(r, g, b, a)
8
+ @red, @green, @blue, @alpha = r, g, b, a
9
+ end
10
+
11
+ def self.from_hex(hex, alpha = nil)
12
+ if (match = hex.downcase.match(/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/))
13
+ r = Integer(match.captures[0], 16) / 255.0
14
+ g = Integer(match.captures[1], 16) / 255.0
15
+ b = Integer(match.captures[2], 16) / 255.0
16
+ elsif (match = hex.downcase.match(/^#?([a-f\d])([a-f\d])([a-f\d])$/))
17
+ r = Integer(match.captures[0] * 2, 16) / 255.0
18
+ g = Integer(match.captures[1] * 2, 16) / 255.0
19
+ b = Integer(match.captures[2] * 2, 16) / 255.0
20
+ else
21
+ raise ArgumentError, "Invalid color syntax: #{hex}"
22
+ end
23
+
24
+ max_digits = 2
25
+
26
+ Color.new(r.round(max_digits), g.round(max_digits), b.round(max_digits), alpha || 1.0)
27
+ end
28
+
29
+ def grayscale?
30
+ @red == @green && @green == @blue
31
+ end
32
+
33
+ def to_s(struct_name, _indent = 0)
34
+ if grayscale?
35
+ "#{struct_name}(white: #{@red}, alpha: #{@alpha})"
36
+ else
37
+ "#{struct_name}(red: #{@red}, green: #{@green}, blue: #{@blue}, alpha: #{@alpha})"
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stylegen
4
+ class LightDarkColor
5
+ def initialize(light, dark)
6
+ @light, @dark = light, dark
7
+ end
8
+
9
+ def to_s(struct_name, indent = 0)
10
+ indent_prefix = " " * indent
11
+
12
+ result = []
13
+ result << "#{struct_name}("
14
+ result << "#{indent_prefix} light: #{@light.to_s(struct_name, indent + 4)},"
15
+ result << "#{indent_prefix} dark: #{@dark.to_s(struct_name, indent + 4)}"
16
+ result << "#{indent_prefix})"
17
+
18
+ result.join("\n")
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/inflector"
4
+ require "stylegen/version"
5
+ require "stylegen/colors"
6
+
7
+ module Stylegen
8
+ class Data
9
+ def initialize(data)
10
+ @data = data
11
+ end
12
+
13
+ def inflector
14
+ @inflector ||= Dry::Inflector.new
15
+ end
16
+
17
+ def version
18
+ Stylegen::VERSION
19
+ end
20
+
21
+ def system_name
22
+ @data["system_name"] || "Theme"
23
+ end
24
+
25
+ def util_method_name
26
+ inflector.camelize_lower(inflector.underscore(system_name))
27
+ end
28
+
29
+ def output_path
30
+ @data["output_path"]
31
+ end
32
+
33
+ def basename
34
+ File.basename(@data["output_path"])
35
+ end
36
+
37
+ def access_level
38
+ @data["access_level"] || "internal"
39
+ end
40
+
41
+ def struct_name
42
+ "#{system_name}Color"
43
+ end
44
+
45
+ def colors
46
+ @data["colors"].each do |key, value|
47
+ yield inflector.camelize_lower(key), generate_color(value)
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def generate_color(data)
54
+ if data.is_a?(String)
55
+ Color.from_hex(data)
56
+ elsif data.key?("color")
57
+ Color.from_hex(data["color"], data["alpha"])
58
+ elsif data.key?("light")
59
+ LightDarkColor.new(
60
+ generate_color(data["light"]),
61
+ generate_color(data["dark"])
62
+ )
63
+ elsif data.key?("base")
64
+ BaseElevatedColor.new(
65
+ generate_color(data["base"]),
66
+ generate_color(data["elevated"])
67
+ )
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stylegen/data"
4
+
5
+ module Stylegen
6
+ class Generator
7
+ def initialize(data)
8
+ @data = Data.new(data)
9
+ @file = File.open(@data.output_path, "w")
10
+ end
11
+
12
+ def out(line)
13
+ @file << line << "\n"
14
+ end
15
+
16
+ def generate
17
+ generate_header
18
+ generate_struct
19
+ generate_colors
20
+ generate_extensions
21
+ end
22
+
23
+ private
24
+
25
+ def generate_header
26
+ out "//"
27
+ out "// #{@data.basename}"
28
+ out "//"
29
+ out "// Autogenerated by stylegen (v#{@data.version})"
30
+ out "// DO NOT EDIT"
31
+ out "//"
32
+ out ""
33
+ out "import UIKit"
34
+ out ""
35
+ end
36
+
37
+ def generate_struct
38
+ out "#{@data.access_level} struct #{@data.struct_name} {"
39
+ out ""
40
+ out " let uiColor: UIColor"
41
+ out ""
42
+ out " fileprivate init(white: CGFloat, alpha: CGFloat) {"
43
+ out " self.uiColor = UIColor(white: white, alpha: alpha)"
44
+ out " }"
45
+ out ""
46
+ out " fileprivate init(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {"
47
+ out " self.uiColor = UIColor(red: red, green: green, blue: blue, alpha: alpha)"
48
+ out " }"
49
+ out ""
50
+ out " fileprivate init(_ color: UIColor) {"
51
+ out " self.uiColor = color"
52
+ out " }"
53
+ out ""
54
+ out " fileprivate init(light: #{@data.struct_name}, dark: #{@data.struct_name}) {"
55
+ out " if #available(iOS 13.0, *) {"
56
+ out " self.uiColor = UIColor(dynamicProvider: { (traits: UITraitCollection) -> UIColor in"
57
+ out " switch traits.userInterfaceStyle {"
58
+ out " case .dark:"
59
+ out " return dark.uiColor"
60
+ out " default:"
61
+ out " return light.uiColor"
62
+ out " }"
63
+ out " })"
64
+ out " } else {"
65
+ out " self.uiColor = light.uiColor"
66
+ out " }"
67
+ out " }"
68
+ out ""
69
+ out " fileprivate init(base: #{@data.struct_name}, elevated: #{@data.struct_name}) {"
70
+ out " if #available(iOS 13.0, *) {"
71
+ out " self.uiColor = UIColor(dynamicProvider: { (traits: UITraitCollection) -> UIColor in"
72
+ out " switch traits.userInterfaceLevel {"
73
+ out " case .elevated:"
74
+ out " return elevated.uiColor"
75
+ out " default:"
76
+ out " return base.uiColor"
77
+ out " }"
78
+ out " })"
79
+ out " } else {"
80
+ out " self.uiColor = base.uiColor"
81
+ out " }"
82
+ out " }"
83
+ out ""
84
+ out "}"
85
+ out ""
86
+ end
87
+
88
+ def generate_colors
89
+ out "#{@data.access_level} extension #{@data.struct_name} {"
90
+ out ""
91
+
92
+ @data.colors do |member, color|
93
+ out " static let #{member} = #{color.to_s(@data.struct_name, 4)}"
94
+ out ""
95
+ end
96
+
97
+ out "}"
98
+ out ""
99
+ end
100
+
101
+ def generate_extensions
102
+ out "#{@data.access_level} extension UIColor {"
103
+ out ""
104
+ out " @inline(__always)"
105
+ out " static func #{@data.util_method_name}(_ color: #{@data.struct_name}) -> UIColor {"
106
+ out " return color.uiColor"
107
+ out " }"
108
+ out ""
109
+ out "}"
110
+ out ""
111
+
112
+ out "#{@data.access_level} extension CGColor {"
113
+ out ""
114
+ out " @inline(__always)"
115
+ out " static func #{@data.util_method_name}(_ color: #{@data.struct_name}) -> CGColor {"
116
+ out " return color.uiColor.cgColor"
117
+ out " }"
118
+ out ""
119
+ out "}"
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,105 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "stylegen configuration",
4
+ "type": "object",
5
+ "definitions": {
6
+ "AbstractColor": {
7
+ "oneOf": [
8
+ {
9
+ "$ref": "#/definitions/HexColor"
10
+ },
11
+ {
12
+ "$ref": "#/definitions/Color"
13
+ },
14
+ {
15
+ "$ref": "#/definitions/BaseElevatedColor"
16
+ },
17
+ {
18
+ "$ref": "#/definitions/LightDarkColor"
19
+ }
20
+ ]
21
+ },
22
+ "HexColor": {
23
+ "type": "string",
24
+ "pattern": "^#?([0-9a-fA-F]{3})([0-9a-fA-F]{3})?$"
25
+ },
26
+ "Color": {
27
+ "type": "object",
28
+ "properties": {
29
+ "color": {
30
+ "$ref": "#/definitions/HexColor"
31
+ },
32
+ "alpha": {
33
+ "type": "number",
34
+ "minimum": 0.0,
35
+ "maximum": 1.0
36
+ }
37
+ },
38
+ "required": ["color"],
39
+ "additionalProperties": false
40
+ },
41
+ "BaseElevatedColor": {
42
+ "type": "object",
43
+ "properties": {
44
+ "base": {
45
+ "$ref": "#/definitions/AbstractColor"
46
+ },
47
+ "elevated": {
48
+ "$ref": "#/definitions/AbstractColor"
49
+ }
50
+ },
51
+ "required": ["base", "elevated"],
52
+ "additionalProperties": false
53
+ },
54
+ "LightDarkColor": {
55
+ "type": "object",
56
+ "properties": {
57
+ "light": {
58
+ "$ref": "#/definitions/AbstractColor"
59
+ },
60
+ "dark": {
61
+ "$ref": "#/definitions/AbstractColor"
62
+ }
63
+ },
64
+ "required": ["light", "dark"],
65
+ "additionalProperties": false
66
+ }
67
+ },
68
+ "properties": {
69
+ "access_level": {
70
+ "type": "string",
71
+ "description": "Access level of the generated Swift code.",
72
+ "enum": [
73
+ "internal",
74
+ "public"
75
+ ]
76
+ },
77
+ "system_name": {
78
+ "type": "string",
79
+ "description": "Name of the design system or theme."
80
+ },
81
+ "output_path": {
82
+ "type": "string",
83
+ "minLength": 1,
84
+ "description": "Path of generated Swift file."
85
+ },
86
+ "colors": {
87
+ "type": "object",
88
+ "description": "Key-value pairs of colors.",
89
+ "patternProperties": {
90
+ "^.*$": {
91
+ "anyOf": [
92
+ {
93
+ "$ref": "#/definitions/AbstractColor"
94
+ }
95
+ ]
96
+ }
97
+ },
98
+ "additionalProperties": false
99
+ }
100
+ },
101
+ "required": [
102
+ "output_path",
103
+ "colors"
104
+ ]
105
+ }
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json_schemer"
4
+
5
+ module Stylegen
6
+ class Validator
7
+ def valid?(config)
8
+ schema.valid?(config)
9
+ end
10
+
11
+ def validate(config)
12
+ errors = []
13
+
14
+ schema.validate(config).each do |v|
15
+ errors << JSONSchemer::Errors.pretty(v) unless v["type"] == "schema"
16
+ end
17
+
18
+ errors
19
+ end
20
+
21
+ private
22
+
23
+ def schema
24
+ @schema ||= JSONSchemer.schema(File.read(File.join(__dir__, "schema.json")))
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stylegen
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "./lib/stylegen/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "stylegen"
7
+ s.version = Stylegen::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Ramon Torres"]
10
+ s.email = ["raymondjavaxx@gmail.com"]
11
+ s.homepage = "https://github.com/raymondjavaxx/stylegen"
12
+ s.description = s.summary = "Tool for generating styling code for iOS apps"
13
+ s.files = `git ls-files`.split("\n")
14
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
16
+ s.require_paths = ["lib"]
17
+ s.license = "MIT"
18
+
19
+ s.add_runtime_dependency "dry-inflector", ">= 0.2.0"
20
+ s.add_runtime_dependency "json_schemer", ">= 0.2.0"
21
+
22
+ s.add_development_dependency "bundler"
23
+ s.add_development_dependency "minitest", ">= 5.14.0"
24
+ s.add_development_dependency "rake"
25
+ s.add_development_dependency "rubocop"
26
+ s.add_development_dependency "rubocop-minitest"
27
+ s.add_development_dependency "rubocop-rake"
28
+
29
+ s.required_ruby_version = ">= 2.4.0"
30
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ gem "minitest"
4
+
5
+ require "minitest/pride"
6
+ require "minitest/autorun"
7
+
8
+ require_relative "../lib/stylegen"
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "helper"
4
+
5
+ class TestBaseElevatedColor < MiniTest::Test
6
+ def test_to_string
7
+ color = Stylegen::BaseElevatedColor.new(
8
+ Stylegen::Color.from_hex("#000000"),
9
+ Stylegen::Color.from_hex("#333333")
10
+ )
11
+
12
+ # Default indentation
13
+
14
+ expected = <<~CODE.chomp
15
+ ThemeColor(
16
+ base: ThemeColor(white: 0.0, alpha: 1.0),
17
+ elevated: ThemeColor(white: 0.2, alpha: 1.0)
18
+ )
19
+ CODE
20
+
21
+ assert_equal expected, color.to_s("ThemeColor")
22
+
23
+ # Additional indentation
24
+
25
+ expected = <<~CODE.chomp
26
+ ThemeColor(
27
+ base: ThemeColor(white: 0.0, alpha: 1.0),
28
+ elevated: ThemeColor(white: 0.2, alpha: 1.0)
29
+ )
30
+ CODE
31
+
32
+ assert_equal expected, color.to_s("ThemeColor", 4)
33
+ end
34
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "helper"
4
+
5
+ class TestColor < MiniTest::Test
6
+ def test_parsing
7
+ color = Stylegen::Color.from_hex("#FF8000")
8
+ assert_equal 1.0, color.red
9
+ assert_equal 0.5, color.green
10
+ assert_equal 0.0, color.blue
11
+ assert_equal 1.0, color.alpha
12
+
13
+ # Optional pound sign
14
+ color = Stylegen::Color.from_hex("FF8000")
15
+ assert_equal 1.0, color.red
16
+ assert_equal 0.5, color.green
17
+ assert_equal 0.0, color.blue
18
+ assert_equal 1.0, color.alpha
19
+
20
+ # Specify alpha
21
+ color = Stylegen::Color.from_hex("#FF8000", 0.5)
22
+ assert_equal 0.5, color.alpha
23
+ end
24
+
25
+ def test_parsing_shorthand_syntax
26
+ color = Stylegen::Color.from_hex("#FC0")
27
+ assert_equal 1.0, color.red
28
+ assert_equal 0.8, color.green
29
+ assert_equal 0.0, color.blue
30
+ assert_equal 1.0, color.alpha
31
+
32
+ # Optional pound sign
33
+ color = Stylegen::Color.from_hex("FC0")
34
+ assert_equal 1.0, color.red
35
+ assert_equal 0.8, color.green
36
+ assert_equal 0.0, color.blue
37
+ assert_equal 1.0, color.alpha
38
+ end
39
+
40
+ def test_grayscale
41
+ color = Stylegen::Color.new(1, 1, 1, 1)
42
+ assert color.grayscale?
43
+
44
+ color = Stylegen::Color.new(1, 1, 0.9, 1)
45
+ refute color.grayscale?
46
+ end
47
+
48
+ def test_to_string
49
+ color = Stylegen::Color.from_hex("#00FF00")
50
+ expected = "ThemeColor(red: 0.0, green: 1.0, blue: 0.0, alpha: 1.0)"
51
+ assert_equal expected, color.to_s("ThemeColor")
52
+
53
+ # Grayscale
54
+ color = Stylegen::Color.from_hex("#FFFFFF")
55
+ expected = "ThemeColor(white: 1.0, alpha: 1.0)"
56
+ assert_equal expected, color.to_s("ThemeColor")
57
+ end
58
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "helper"
4
+
5
+ class TestLightDarkColor < MiniTest::Test
6
+ def test_to_string
7
+ color = Stylegen::LightDarkColor.new(
8
+ Stylegen::Color.from_hex("#FFFFFF"),
9
+ Stylegen::Color.from_hex("#333333")
10
+ )
11
+
12
+ # Default indentation
13
+
14
+ expected = <<~CODE.chomp
15
+ ThemeColor(
16
+ light: ThemeColor(white: 1.0, alpha: 1.0),
17
+ dark: ThemeColor(white: 0.2, alpha: 1.0)
18
+ )
19
+ CODE
20
+
21
+ assert_equal expected, color.to_s("ThemeColor")
22
+
23
+ # Additional indentation
24
+
25
+ expected = <<~CODE.chomp
26
+ ThemeColor(
27
+ light: ThemeColor(white: 1.0, alpha: 1.0),
28
+ dark: ThemeColor(white: 0.2, alpha: 1.0)
29
+ )
30
+ CODE
31
+
32
+ assert_equal expected, color.to_s("ThemeColor", 4)
33
+ end
34
+ end
metadata ADDED
@@ -0,0 +1,185 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stylegen
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ramon Torres
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-01-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dry-inflector
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: json_schemer
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.2.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.2.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 5.14.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 5.14.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-minitest
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: Tool for generating styling code for iOS apps
126
+ email:
127
+ - raymondjavaxx@gmail.com
128
+ executables:
129
+ - stylegen
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - ".github/workflows/ci.yml"
134
+ - ".gitignore"
135
+ - ".rubocop.yml"
136
+ - Gemfile
137
+ - Gemfile.lock
138
+ - LICENSE
139
+ - README.md
140
+ - Rakefile
141
+ - bin/stylegen
142
+ - lib/stylegen.rb
143
+ - lib/stylegen/colors.rb
144
+ - lib/stylegen/colors/base_elevated_color.rb
145
+ - lib/stylegen/colors/color.rb
146
+ - lib/stylegen/colors/light_dark_color.rb
147
+ - lib/stylegen/data.rb
148
+ - lib/stylegen/generator.rb
149
+ - lib/stylegen/schema.json
150
+ - lib/stylegen/validator.rb
151
+ - lib/stylegen/version.rb
152
+ - stylegen.gemspec
153
+ - test/helper.rb
154
+ - test/test_base_elevated_color.rb
155
+ - test/test_color.rb
156
+ - test/test_light_dark_color.rb
157
+ homepage: https://github.com/raymondjavaxx/stylegen
158
+ licenses:
159
+ - MIT
160
+ metadata: {}
161
+ post_install_message:
162
+ rdoc_options: []
163
+ require_paths:
164
+ - lib
165
+ required_ruby_version: !ruby/object:Gem::Requirement
166
+ requirements:
167
+ - - ">="
168
+ - !ruby/object:Gem::Version
169
+ version: 2.4.0
170
+ required_rubygems_version: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - ">="
173
+ - !ruby/object:Gem::Version
174
+ version: '0'
175
+ requirements: []
176
+ rubyforge_project:
177
+ rubygems_version: 2.7.6
178
+ signing_key:
179
+ specification_version: 4
180
+ summary: Tool for generating styling code for iOS apps
181
+ test_files:
182
+ - test/helper.rb
183
+ - test/test_base_elevated_color.rb
184
+ - test/test_color.rb
185
+ - test/test_light_dark_color.rb