stylish 0.0.2 → 0.3.0

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,97 @@
1
+ command "import external theme" do |c|
2
+ c.syntax = "stylish import SOURCE DESTINATION [OPTIONS]"
3
+ c.description = "import a theme"
4
+
5
+ c.option '--importer IMPORTER', String, 'The importer class to use'
6
+ c.option '--output-path PATH', String, 'Which folder to store the resulting theme in'
7
+ c.option '--clean', 'Whether or not to remove the output path'
8
+
9
+ c.action do |args, options|
10
+ require 'stylish/theme/importer'
11
+
12
+ source = Pathname(args.shift)
13
+ destination = args.shift
14
+ destination ||= "stylish-export"
15
+
16
+ options.default(importer: "startup_framework",
17
+ output_path: Stylish.pwd.join("vendor/themes/startup_framework"))
18
+
19
+ importer = Stylish::Theme::Importer.load_by_type(options.importer)
20
+
21
+ job = importer.new(source, output_path: options.output_path, clean: options.clean)
22
+
23
+ job.prompt_for_settings()
24
+
25
+ job.run()
26
+ end
27
+ end
28
+
29
+ command "prepare theme" do |c|
30
+ c.syntax = "stylish prepare theme THEME [OPTIONS]"
31
+ c.description = "take a stylish theme and load it into the desired format for your current project"
32
+
33
+ c.option '--target TARGET', String, 'What type of project will use the theme?'
34
+ c.option '--output-path FILE', String, 'Where to put the theme?'
35
+
36
+ c.action do |args, options|
37
+ require 'stylish/theme/importer'
38
+ require 'stylish/theme/exporter'
39
+
40
+ options.default(output_path: Pathname(Dir.pwd).join('vendor'))
41
+
42
+ theme_name = args.first
43
+ theme = Stylish::Theme.new(Stylish.lib_root.join('../vendor/themes', theme_name))
44
+ output_path = Pathname(options.output_path)
45
+ importer = Stylish::Theme::Importer.load_by_type(theme_name)
46
+
47
+ FileUtils.cp_r(theme.root, output_path)
48
+
49
+ theme = Stylish::Theme.new(output_path.join(theme_name))
50
+
51
+ target = options.target.to_s.to_sym
52
+
53
+ if target == :middleman
54
+ helper = theme.root.join('assets/stylesheets/startup-framework/dependencies/startup-framework/helper.less')
55
+
56
+ helper_content = helper.read
57
+
58
+ helper_content.sub!("../fonts/", "/fonts/")
59
+
60
+ helper.open("w+") {|fh| fh.write(helper_content)}
61
+
62
+ files = Dir[theme.root.join('views','components','**/*.html')]
63
+
64
+ src_values = []
65
+
66
+ files.map! {|file| Pathname(file) }
67
+
68
+ files.each do |path|
69
+ fragment = Nokogiri::HTML.fragment(path.read)
70
+ image_tags = fragment.css("img")
71
+
72
+ src_values += image_tags.map do |tag|
73
+ src = tag.attr('src')
74
+ original = src.dup
75
+
76
+ conversions = importer.const_get(:ImagePathConversions)
77
+
78
+ conversions.each do |pattern, replacement|
79
+ src.gsub! pattern, replacement
80
+ end
81
+
82
+ puts "== Replacing #{ original } with #{ src } value"
83
+ tag['src'] = "<%= image_path('#{src}') %>".html_safe
84
+ end
85
+
86
+ path.open("w+") do |f|
87
+ html = fragment.to_html
88
+ html.gsub! '&lt;%=%20', '<%= '
89
+ html.gsub! '%20%&gt;', ' %>'
90
+ f.write(html)
91
+ end
92
+
93
+ FileUtils.mv(path, path.to_s + '.erb')
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,31 @@
1
+ class Stylish::Server
2
+ def self.start(options={})
3
+ require 'rack'
4
+ require 'rack/server'
5
+ require 'pry'
6
+
7
+
8
+ Stylish.config.apply(:library_path => Pathname(options.library_path))
9
+
10
+ config = Stylish.lib_root.join 'stylish', 'api.ru'
11
+
12
+ Rack::Server.start :config => config.to_s,
13
+ :Port => options.port,
14
+ :Host => options.host
15
+
16
+ end
17
+ end
18
+
19
+ command "server" do |c|
20
+ c.syntax = "stylish server [OPTIONS]"
21
+ c.description = "start the stylish server"
22
+
23
+ c.option '--port PORT', String, 'Which port to listen on?'
24
+ c.option '--host HOSTNAME', String, 'Which host to listen on?'
25
+ c.option '--library-path PATH', nil, 'Which library should we load?'
26
+
27
+ c.action do |args, options|
28
+ options.default(:port => 8090, :host => "0.0.0.0", :library_path => Dir.pwd)
29
+ Stylish::Server.start(options)
30
+ end
31
+ end
@@ -2,36 +2,42 @@ module Stylish
2
2
  class Configuration
3
3
  include Singleton
4
4
 
5
+ Defaults = {}
6
+
5
7
  def self.method_missing(meth, *args, &block)
8
+ binding.pry
9
+
6
10
  if instance.respond_to?(meth)
7
- instance.send(meth, *args, &block)
8
- else
9
- super
11
+ return instance.send meth, *args, &block
10
12
  end
13
+
14
+ nil
15
+ end
16
+
17
+ def respond_to?(*args)
18
+ current.send(:key?, args.first) || current.send(:respond_to?, *args)
11
19
  end
12
20
 
13
21
  def method_missing(meth, *args, &block)
14
- if config.respond_to?(meth)
15
- config.send(meth, *args, &block)
16
- else
17
- super
18
- end
22
+ return current[meth] if current.key?(meth)
23
+ super
19
24
  end
20
25
 
21
- def config
22
- @config ||= Hashie::Mash.new
26
+ def apply(object={})
27
+ current.tap {|c| c.merge!(object) }
23
28
  end
24
29
 
25
- def load_from_file(path)
26
- path = path.to_s.to_pathname
30
+ def public
31
+ current.slice(:library_path)
32
+ end
27
33
 
28
- payload = if path.extname == ".yml"
29
- YAML.load path.read
30
- elsif path.extname == ".json"
31
- JSON.parse path.read
34
+ def current
35
+ @current ||= Hashie::Mash.new(Defaults).tap do |c|
36
+ ENV.each do |key, value|
37
+ key = key.to_s.downcase.to_sym
38
+ c[key] = value
39
+ end
32
40
  end
33
-
34
- config.merge!(payload)
35
41
  end
36
42
  end
37
43
  end
@@ -1,10 +1,47 @@
1
- require 'hashie'
2
- require 'pathname'
1
+ require 'set'
2
+
3
+ class Set
4
+ def push(*args)
5
+ send(:<<, *args)
6
+ end
7
+ end
3
8
 
4
9
  class Hash
5
10
  def to_mash
6
11
  Hashie::Mash.new(self)
7
12
  end
13
+
14
+ def lookup_path dot_separated_path, create=false
15
+ parts = dot_separated_path.to_s.split('.')
16
+
17
+ parts.reduce(self) do |memo, part|
18
+ memo && memo[part.to_sym] ||= memo[part.to_s] || (create if create)
19
+ end
20
+ end
21
+
22
+ def make_path dot_separated_path, blank_value, overwrite=false
23
+ dot_separated_path = dot_separated_path.to_s
24
+ existing = lookup_path(dot_separated_path)
25
+
26
+ return existing if existing && !overwrite
27
+
28
+ parts = dot_separated_path.split(".")
29
+
30
+ current = self
31
+
32
+ if parts.length == 1
33
+ return self[parts.first] ||= blank_value
34
+ end
35
+
36
+ key = parts.pop
37
+
38
+ parts.each do |part|
39
+ current = current[part.to_sym] = current.delete(part.to_s) || {}
40
+ end
41
+
42
+ current[key.to_sym] = blank_value
43
+ lookup_path(dot_separated_path, false)
44
+ end
8
45
  end
9
46
 
10
47
  class Pathname
@@ -1,12 +1,4 @@
1
1
  module Stylish
2
2
  class Engine < ::Rails::Engine
3
- initializer 'stylish.developer_mode' do |app|
4
- sprockets = app.assets
5
-
6
- Stylish::Developer.config do |cfg|
7
- cfg.root = app.root
8
- cfg.environment = sprockets
9
- end
10
- end
11
3
  end
12
4
  end
@@ -0,0 +1,33 @@
1
+ module Stylish
2
+ class MiddlemanExtension < ::Middleman::Extension
3
+ def self.activate_stylish_extension
4
+ ::Middleman::Extensions.register(:stylish, Stylish::MiddlemanExtension)
5
+ end
6
+
7
+ option :theme, String, 'The name of the theme'
8
+
9
+ helpers do
10
+ def stylish
11
+ theme_root = Pathname(root).join('vendor').join extensions[:stylish].options[:theme]
12
+ @stylish ||= Stylish::Theme.new(theme_root)
13
+ end
14
+ end
15
+
16
+ def after_configuration
17
+ import_stylish_images_and_fonts
18
+ end
19
+
20
+ def import_stylish_images_and_fonts
21
+ environment = app.stylish.compiler
22
+ trusted_paths = environment.paths.select { |p| p.end_with?('images') || p.end_with?('fonts') }
23
+ trusted_paths.each do |load_path|
24
+ environment.each_entry(load_path) do |path|
25
+ if path.file? && !path.basename.to_s.start_with?('_')
26
+ logical_path = path.sub(/^#{load_path}/, '')
27
+ environment.imported_assets << Middleman::Sprockets::ImportedAsset.new(logical_path)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,42 @@
1
+ module Stylish
2
+ module Rails
3
+ module ViewHelpers
4
+ # used by a layout to load the layout confiig it depends on.
5
+ # this will help build the dependency manifests properly.
6
+ #
7
+ # @param [String] the identifier for the layout
8
+ def load_theme_layout layout_identifier
9
+ end
10
+
11
+ # used by a page to load the components it will depend on. this
12
+ # helps us build the dependency manifests properly
13
+ def load_theme_components *component_identifiers
14
+ end
15
+
16
+ # sequentially renders every component for this page
17
+ def render_all_components
18
+ end
19
+
20
+ # renders a component. used in the page layouts.
21
+ def render_component component_identifier
22
+ end
23
+
24
+ # (see #javascript_imports_for)
25
+ def stylesheet_imports_for(page_identifier, options={})
26
+ end
27
+
28
+ # Returns a list of sprockets logical paths to satisfy
29
+ # the dependencies for a given stylish layout. These values can
30
+ # be used to dynamically generate JS content using ERB, or in a generator
31
+ # which will just output a sprockets manifest.
32
+ #
33
+ # This method will depend on the page having declared its dependency on
34
+ # a layout, and the components it depends on.
35
+ #
36
+ # @param [String] the slug for the stylish page which will be using the requested components
37
+ # @return [Array] a list of values which can be required in a sprockets manifest
38
+ def javascript_imports_for(page_identifier, options={})
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,42 @@
1
+ module Stylish
2
+ class Theme
3
+ attr_accessor :root, :options, :manifest, :manifest_path, :compiler
4
+
5
+ def initialize(root, options={})
6
+ @options = options
7
+ @root = Pathname(root).expand_path
8
+ @manifest_path = options.fetch(:manifest_path) { root.join('stylish.yml') }
9
+
10
+ raise 'Manifest file not found. Please provide a root directory in which stylish.json can be found' unless manifest_path.exist?
11
+
12
+ @manifest = Hashie::Mash.new YAML.load_file(manifest_path)
13
+
14
+ setup_compiler rescue nil
15
+ end
16
+
17
+ def apply_manifest values={}
18
+ @manifest.merge!(values)
19
+ end
20
+
21
+ def dependency_paths
22
+ Array(manifest.dependency_paths).map {|path| root.join(path) }
23
+ end
24
+
25
+ def import_paths
26
+ Array(manifest.import_paths).map {|path| root.join(path) }
27
+ end
28
+
29
+ def setup_compiler
30
+ @compiler ||= Stylish.sprockets.dup.tap do |env|
31
+ dependency_paths.each {|p| env.append_path(p) }
32
+
33
+ if defined?(::Less)
34
+ (import_paths.map(&:to_s) - Less.paths.map(&:to_s)).each do |path|
35
+ Less.paths << path
36
+ end
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,4 @@
1
+ module Stylish
2
+ class Theme::Component
3
+ end
4
+ end
@@ -0,0 +1,15 @@
1
+ module Stylish
2
+ class Theme::Exporter
3
+ attr_accessor :options, :source, :destination, :theme
4
+
5
+ def initialize(source, options={})
6
+ @source = Pathname(source)
7
+ @options = options
8
+ end
9
+
10
+ def run
11
+ replace_path_placeholders
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ module Stylish
2
+ module Exporters
3
+ class Middleman < Stylish::Theme::Exporter
4
+
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,175 @@
1
+ require 'set'
2
+
3
+ module Stylish
4
+ class Theme::Importer
5
+
6
+ attr_reader :options, :exports, :paths, :config
7
+ attr_accessor :source, :destination, :name, :dependency_paths, :import_paths
8
+
9
+ def initialize(source, options={})
10
+ @source = Pathname(source)
11
+ @options = options
12
+
13
+
14
+ @name = options.fetch(:name, "stylish-theme")
15
+ @paths = {
16
+ output_path: Pathname(options[:output_path] || "#{ Dir.pwd }#{ name }")
17
+ }
18
+
19
+ clean if options[:clean]
20
+
21
+ @exports = {}.to_mash
22
+ @dependency_paths = Set.new
23
+ @import_paths = Set.new
24
+
25
+ @config = {}.to_mash
26
+
27
+ map_source_paths
28
+ prepare_output_paths
29
+
30
+ if(options[:run] == true)
31
+ run
32
+ end
33
+
34
+ end
35
+
36
+ DefaultRunCommands = %w(
37
+ move_common_javascript_dependencies_into_global_theme
38
+ move_common_stylesheet_dependencies_into_global_theme
39
+ extract_component_dependency_stylesheets
40
+ extract_component_dependency_javascripts
41
+ extract_component_markup
42
+ write_manifest
43
+ )
44
+
45
+ DefaultRunCommands.each do |meth|
46
+ define_method(meth) { raise NotImplementedError, "Importer class responsible for implementing: #{ meth }" } unless method_defined?(meth)
47
+ end
48
+
49
+ def run
50
+ DefaultRunCommands.each do |cmd|
51
+ send(cmd)
52
+ end
53
+ end
54
+
55
+ def manifest
56
+ exports.to_hash.merge(
57
+ dependency_paths: dependency_paths.to_a.map {|path| Pathname(path).relative_path_from(output_path).to_s },
58
+ import_paths: import_paths.to_a.map {|path| Pathname(path).relative_path_from(output_path).to_s }
59
+ )
60
+ end
61
+
62
+
63
+ def prepare
64
+ map_source_paths
65
+ prepare_output_paths
66
+ end
67
+
68
+ def prompts
69
+ {}
70
+ end
71
+
72
+ def clean
73
+ FileUtils.rm_rf(output_path)
74
+ end
75
+
76
+ def prompt_for_settings
77
+ if respond_to?(:ask)
78
+ prompts.each do |var, question|
79
+ self.options[var] = ask(question, String)
80
+ end
81
+ end
82
+ end
83
+
84
+ def method_missing meth, *args, &block
85
+ return paths[meth.to_sym] if meth.to_s.match(/_path$/) && paths.key?(meth.to_sym)
86
+ config.lookup_path(meth.to_s) || exports.lookup_path(meth.to_s) || super
87
+ end
88
+
89
+ def respond_to?(*args)
90
+ paths.key?(args.first.to_sym) || super
91
+ end
92
+
93
+ def set key, value
94
+ key = key.to_s
95
+ config.make_path(key, value)
96
+ end
97
+
98
+ def export key, value
99
+ key = key.to_s
100
+ exports.make_path(key, value, true)
101
+ end
102
+
103
+ def push key, value
104
+ key = key.to_s
105
+ exports.make_path(key, [])
106
+ exports.lookup_path(key) << value
107
+ end
108
+
109
+ def define_path identifier, value
110
+ value = Pathname(value)
111
+ @paths[identifier.to_sym] = value
112
+ value
113
+ end
114
+
115
+ def prepare_output_paths
116
+ FileUtils.mkdir_p output_path
117
+ FileUtils.mkdir_p components_output_path
118
+ FileUtils.mkdir_p layouts_output_path
119
+ FileUtils.mkdir_p javascripts_output_path.join('dependencies')
120
+ FileUtils.mkdir_p stylesheets_output_path.join('dependencies')
121
+ FileUtils.mkdir_p images_output_path
122
+ FileUtils.mkdir_p fonts_output_path
123
+
124
+ exports.component_categories.each do |category|
125
+ FileUtils.mkdir_p components_output_path.join(category.downcase.parameterize)
126
+ FileUtils.mkdir_p javascripts_output_path.join(category.downcase.parameterize)
127
+ FileUtils.mkdir_p stylesheets_output_path.join(category.downcase.parameterize)
128
+ end
129
+ end
130
+
131
+ def write_manifest
132
+ output_path.join("stylish.yml").open("w+") {|fh| fh.write(manifest.to_yaml) }
133
+ end
134
+
135
+ def components_output_path
136
+ output_path.join('views/components')
137
+ end
138
+
139
+ def layouts_output_path
140
+ output_path.join('views/layouts')
141
+ end
142
+
143
+ def stylesheets_output_path
144
+ output_path.join("assets/stylesheets/#{name}")
145
+ end
146
+
147
+ def javascripts_output_path
148
+ output_path.join("assets/javascripts/#{name}")
149
+ end
150
+
151
+ def images_output_path
152
+ output_path.join("assets/images/#{name}")
153
+ end
154
+
155
+ def fonts_output_path
156
+ output_path.join("assets/fonts/#{name}")
157
+ end
158
+
159
+ # Loads a specific importer configuration class
160
+ #
161
+ # @param [String] which importer config to use
162
+ # will reference a .rb file in the configured importer definition paths
163
+ def self.load_by_type(type)
164
+ importer_file = Stylish.lib_root
165
+ .join("stylish/theme/importers")
166
+ .join(type.to_s + '.rb')
167
+
168
+ raise "Invalid Importer" unless importer_file.exist?
169
+
170
+ require(importer_file)
171
+
172
+ (Stylish::Importers.const_get("#{ type }_importer".camelize) rescue nil) || (Stylish::Importers.const_get("#{ type }".camelize))
173
+ end
174
+ end
175
+ end