forge 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/.document +5 -0
  2. data/.gitmodules +3 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +24 -0
  5. data/Gemfile.lock +81 -0
  6. data/LICENSE +20 -0
  7. data/README.md +24 -0
  8. data/Rakefile +53 -0
  9. data/VERSION +1 -0
  10. data/bin/forge +12 -0
  11. data/features/create.feature +34 -0
  12. data/features/link.feature +14 -0
  13. data/features/step_definitions/forge_steps.rb +38 -0
  14. data/features/support/env.rb +17 -0
  15. data/forge.gemspec +135 -0
  16. data/layouts/config/config.json.erb +13 -0
  17. data/layouts/config/stylesheet_header.erb +11 -0
  18. data/layouts/default/functions/functions.php.erb +21 -0
  19. data/layouts/default/stylesheets/_reset.scss +5 -0
  20. data/layouts/default/stylesheets/_typography.scss +5 -0
  21. data/layouts/default/stylesheets/style.css.scss.erb +28 -0
  22. data/layouts/default/templates/404.php.erb +10 -0
  23. data/layouts/default/templates/archive.php.erb +11 -0
  24. data/layouts/default/templates/attachment.php.erb +34 -0
  25. data/layouts/default/templates/comments.php +2 -0
  26. data/layouts/default/templates/footer.php +9 -0
  27. data/layouts/default/templates/header.php.erb +30 -0
  28. data/layouts/default/templates/index.php +6 -0
  29. data/layouts/default/templates/page.php +18 -0
  30. data/layouts/default/templates/partials/loop.php.erb +30 -0
  31. data/layouts/default/templates/search.php.erb +14 -0
  32. data/layouts/default/templates/sidebar.php +9 -0
  33. data/layouts/default/templates/single.php.erb +32 -0
  34. data/layouts/lib/forge-settings/README.md +43 -0
  35. data/layouts/lib/forge-settings/classes/settings.php +11 -0
  36. data/layouts/lib/forge-settings/classes/settings/collection.php +190 -0
  37. data/layouts/lib/forge-settings/classes/settings/option.php +125 -0
  38. data/layouts/lib/forge-settings/classes/settings/option/select.php +30 -0
  39. data/layouts/lib/forge-settings/classes/settings/option/text.php +15 -0
  40. data/layouts/lib/forge-settings/classes/settings/section.php +56 -0
  41. data/lib/forge.rb +11 -0
  42. data/lib/forge/builder.rb +165 -0
  43. data/lib/forge/cli.rb +86 -0
  44. data/lib/forge/config.rb +63 -0
  45. data/lib/forge/error.rb +8 -0
  46. data/lib/forge/generator.rb +128 -0
  47. data/lib/forge/guard.rb +57 -0
  48. data/lib/forge/project.rb +91 -0
  49. data/lib/forge/version.rb +3 -0
  50. data/lib/guard/forge/assets.rb +31 -0
  51. data/lib/guard/forge/config.rb +31 -0
  52. data/lib/guard/forge/functions.rb +31 -0
  53. data/lib/guard/forge/templates.rb +28 -0
  54. data/spec/lib/forge/config_spec.rb +79 -0
  55. data/spec/lib/forge/project_spec.rb +34 -0
  56. data/spec/spec_helper.rb +13 -0
  57. metadata +263 -0
@@ -0,0 +1,125 @@
1
+ <?php
2
+
3
+ abstract class Settings_Option {
4
+ protected $_name, $_valid_values, $_value, $_type, $_default_value,
5
+ $_tab, $_label, $_description, $_parent_name, $_validation_function;
6
+
7
+ public function name( $name = NULL ) {
8
+ if ( NULL === $name )
9
+ return $this->_name;
10
+
11
+ $this->_name = $name;
12
+ return $this;
13
+ }
14
+
15
+ public function valid_values( $valid_values = NULL ) {
16
+ if ( NULL === $valid_values )
17
+ return $this->_valid_values;
18
+
19
+ $this->_valid_values = $valid_values;
20
+ return $this;
21
+ }
22
+
23
+ public function value( $value = NULL ) {
24
+ if ( NULL === $value ) {
25
+ return $this->_value;
26
+ }
27
+
28
+ $this->_value = $value;
29
+ return $this;
30
+ }
31
+
32
+ public function type( $type = NULL ) {
33
+ if ( NULL === $type )
34
+ return $this->_type;
35
+
36
+ $this->_type = $type;
37
+ return $this;
38
+ }
39
+
40
+ public function default_value( $default_value = NULL ) {
41
+ if ( NULL === $default_value )
42
+ return $this->_default_value;
43
+
44
+ $this->_default_value = $default_value;
45
+ return $this;
46
+ }
47
+
48
+ public function tab( $tab = NULL ) {
49
+ if ( NULL === $tab )
50
+ return $this->_tab;
51
+
52
+ $this->_tab = $tab;
53
+ return $this;
54
+ }
55
+
56
+ public function label( $label = NULL ) {
57
+ if ( NULL === $label )
58
+ return $this->_label;
59
+
60
+ $this->_label = $label;
61
+ return $this;
62
+ }
63
+
64
+ public function description( $description = NULL ) {
65
+ if ( NULL === $description )
66
+ return $this->_description;
67
+
68
+ $this->_description = $description;
69
+ return $this;
70
+ }
71
+
72
+ public function parent_name( $parent_name = NULL ) {
73
+ if ( NULL === $parent_name )
74
+ return $this->_parent_name;
75
+
76
+ $this->_parent_name = $parent_name;
77
+ return $this;
78
+ }
79
+
80
+ public function section( $section = NULL ) {
81
+ if ( NULL === $section )
82
+ return $this->_section;
83
+
84
+ $this->_section = $section;
85
+ return $this;
86
+ }
87
+
88
+ public function validation_function( $validation_function = NULL ) {
89
+ if ( NULL === $validation_function )
90
+ return $this->_validation_function;
91
+
92
+ $this->_validation_function = $validation_function;
93
+ return $this;
94
+ }
95
+
96
+ // The HTML ID takes the form 'parentname-optionname'
97
+ protected function html_id() {
98
+ return $this->parent_name() . '-' . $this->name();
99
+ }
100
+
101
+ // Name takes the form 'parentname[optionname]'
102
+ protected function html_name() {
103
+ return $this->parent_name() . '[' . $this->name() . ']';
104
+ }
105
+
106
+ public function register() {
107
+ add_settings_field(
108
+ $this->name(),
109
+ $this->label(),
110
+ array( &$this, 'to_html' ),
111
+ $this->parent_name(),
112
+ $this->section() );
113
+ }
114
+
115
+ public function validate( $value ) {
116
+ if ( $validation_function = $this->validation_function() ) {
117
+ return $validation_function( $value );
118
+ } else {
119
+ return $this->standard_validation( $value );
120
+ }
121
+ }
122
+
123
+ abstract public function to_html();
124
+ abstract protected function standard_validation( $value );
125
+ }
@@ -0,0 +1,30 @@
1
+ <?php
2
+
3
+ class Settings_Option_Select extends Settings_Option {
4
+ public function to_html() {
5
+ $id = $this->html_id();
6
+ $name = $this->html_name();
7
+
8
+ $output = "<select id='$id' name='$name'>";
9
+
10
+ foreach ( $this->valid_values() as $value => $text ) {
11
+ // If this value is selected, mark it so
12
+ $selected = selected( $this->value(), $value, false );
13
+
14
+ $output .= "<option value='$value' $selected >$text</option>";
15
+ }
16
+
17
+ $output .= "</select>";
18
+
19
+ echo $output;
20
+ }
21
+
22
+ protected function standard_validation( $value ) {
23
+ $valid_values = $this->valid_values();
24
+ if ( array_key_exists( $value, $valid_values ) ) {
25
+ return $value;
26
+ }
27
+
28
+ return $this->default_value();
29
+ }
30
+ }
@@ -0,0 +1,15 @@
1
+ <?php
2
+
3
+ class Settings_Option_Text extends Settings_Option {
4
+ public function to_html() {
5
+ $id = $this->html_id();
6
+ $name = $this->html_name();
7
+ $value = $this->value();
8
+
9
+ echo "<input type='text' id='$id' name='$name' value='$value' />";
10
+ }
11
+
12
+ protected function standard_validation( $value ) {
13
+ return trim( $value );
14
+ }
15
+ }
@@ -0,0 +1,56 @@
1
+ <?php
2
+
3
+ class Settings_Section {
4
+ protected $_id, $_title, $_description, $_parent_name;
5
+
6
+ public function __construct( $id, $title, $description, $parent_name ) {
7
+ $this->id( $id );
8
+ $this->title( $title );
9
+ $this->description( $description );
10
+ $this->parent_name( $parent_name );
11
+ }
12
+
13
+ public function id( $id = NULL ) {
14
+ if ( NULL === $id )
15
+ return $this->_id;
16
+
17
+ $this->_id = $id;
18
+ return $this;
19
+ }
20
+
21
+ public function title( $title = NULL ) {
22
+ if ( NULL === $title )
23
+ return $this->_title;
24
+
25
+ $this->_title = $title;
26
+ return $this;
27
+ }
28
+
29
+ public function description( $description = NULL ) {
30
+ if ( NULL === $description )
31
+ return $this->_description;
32
+
33
+ $this->_description = $description;
34
+ return $this;
35
+ }
36
+
37
+ public function parent_name( $parent_name = NULL ) {
38
+ if ( NULL === $parent_name )
39
+ return $this->_parent_name;
40
+
41
+ $this->_parent_name = $parent_name;
42
+ return $this;
43
+ }
44
+
45
+ public function description_html() {
46
+ echo "<p>{$this->description()}</p>";
47
+ }
48
+
49
+ public function register() {
50
+ add_settings_section(
51
+ $this->id(),
52
+ $this->title(),
53
+ array( &$this, 'description_html' ),
54
+ $this->parent_name() );
55
+ }
56
+ }
@@ -0,0 +1,11 @@
1
+ require 'forge/error'
2
+
3
+ module Forge
4
+ ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
5
+ autoload :Guard, 'forge/guard'
6
+ autoload :CLI, 'forge/cli'
7
+ autoload :Project, 'forge/project'
8
+ autoload :Builder, 'forge/builder'
9
+ autoload :Generator, 'forge/generator'
10
+ autoload :Config, 'forge/config'
11
+ end
@@ -0,0 +1,165 @@
1
+ require 'sprockets'
2
+ require 'sprockets-sass'
3
+ require 'sass'
4
+ require 'zip/zip'
5
+ require 'compass'
6
+
7
+ module Forge
8
+ class Builder
9
+ def initialize(project)
10
+ @project = project
11
+ @task = project.task
12
+ @templates_path = @project.templates_path
13
+ @assets_path = @project.assets_path
14
+ @functions_path = @project.functions_path
15
+ @includes_path = @project.includes_path
16
+
17
+ init_sprockets
18
+ end
19
+
20
+ # Runs all the methods necessary to build a completed project
21
+ def build
22
+ clean_build_directory
23
+ copy_templates
24
+ copy_functions
25
+ build_assets
26
+ end
27
+
28
+ # Use the rubyzip library to build a zip from the generated source
29
+ def zip
30
+ basename = File.basename(@project.root)
31
+
32
+ Zip::ZipFile.open(get_output_filename(basename), Zip::ZipFile::CREATE) do |zip|
33
+ # Get all filenames in the build directory recursively
34
+ filenames = Dir[File.join(@project.build_path, '**', '*')]
35
+
36
+ # Remove the build directory path from the filename
37
+ filenames.collect! {|path| path.gsub(/#{@project.build_path}\//, '')}
38
+
39
+ # Add each file in the build directory to the zip file
40
+ filenames.each do |filename|
41
+ zip.add File.join(basename, filename), File.join(@project.build_path, filename)
42
+ end
43
+ end
44
+ end
45
+
46
+ # Empty out the build directory
47
+ def clean_build_directory
48
+ FileUtils.rm_rf Dir.glob(File.join(@project.build_path, '*'))
49
+ end
50
+
51
+ def clean_templates
52
+ # TODO: cleaner way of removing templates only?
53
+ Dir.glob(File.join(@project.build_path, '*.php')).each do |path|
54
+ FileUtils.rm path unless path.include?('functions.php')
55
+ end
56
+ end
57
+
58
+ def copy_templates
59
+ template_paths.each do |template_path|
60
+ FileUtils.cp template_path, @project.build_path unless File.directory?(template_path)
61
+ end
62
+ end
63
+
64
+ def copy_functions
65
+ FileUtils.cp_r File.join(@functions_path, 'functions.php'), @project.build_path
66
+ end
67
+
68
+ def clean_includes
69
+ FileUtils.rm_rf File.join(@project.build_path, 'includes')
70
+ end
71
+
72
+ def copy_includes
73
+ unless Dir.glob(File.join(@includes_path, '*')).empty?
74
+ FileUtils.cp_r @includes_path, @project.build_path
75
+ end
76
+ end
77
+
78
+ def clean_images
79
+ FileUtils.rm_rf File.join(@project.build_path, 'images')
80
+ end
81
+
82
+ def build_assets
83
+ [['style.css'], ['js', 'theme.js']].each do |asset|
84
+ destination = File.join(@project.build_path, asset)
85
+
86
+ sprocket = @sprockets.find_asset(asset.last)
87
+
88
+ sprockets_error = false
89
+
90
+ # Catch any sprockets errors and continue the process
91
+ begin
92
+ FileUtils.mkdir_p(File.dirname(destination)) unless File.directory?(File.dirname(destination))
93
+ sprocket.write_to(destination) unless sprocket.nil?
94
+
95
+ if asset.last == 'style.css' && (not sprockets_error)
96
+ @task.prepend_file destination, @project.parse_erb(stylesheet_header)
97
+ end
98
+ rescue Exception => e
99
+ @task.say "Error while building #{asset.last}:"
100
+ @task.say e.message, Thor::Shell::Color::RED
101
+ File.open(destination, 'w') do |file|
102
+ file.puts(e.message)
103
+ end
104
+
105
+ # Re-initializing sprockets to prevent further errors
106
+ # TODO: This is done for lack of a better solution
107
+ init_sprockets
108
+ end
109
+ end
110
+
111
+ # Copy the images directory over
112
+ FileUtils.cp_r File.join(@assets_path, 'images'), File.join(@project.build_path)
113
+ end
114
+
115
+ private
116
+
117
+ def init_sprockets
118
+ @sprockets = Sprockets::Environment.new
119
+
120
+ ['javascripts', 'stylesheets'].each do |dir|
121
+ @sprockets.append_path File.join(@assets_path, dir)
122
+ end
123
+
124
+
125
+ # Add all compass frameworks to the sass path
126
+ # TODO: This feels really hacky - is there a better way?
127
+ Compass::Frameworks::ALL.each do |framework|
128
+ Sass::Engine::DEFAULT_OPTIONS[:load_paths] << framework.stylesheets_directory
129
+ end
130
+
131
+ @sprockets.context_class.instance_eval do
132
+ def config
133
+ return {:name => 'asd'}
134
+ p "CALLING CONFIG"
135
+ @project.config
136
+ end
137
+ end
138
+ end
139
+
140
+ def template_paths
141
+ Dir.glob(File.join(@templates_path, '**', '*'))
142
+ end
143
+
144
+ # Generate a unique filename for the zip output
145
+ def get_output_filename(basename)
146
+ filename = "#{basename}.zip"
147
+
148
+ i = 1
149
+ while File.exists?(filename)
150
+ filename = "#{basename}(#{i}).zip"
151
+ i += 1
152
+ end
153
+
154
+ filename
155
+ end
156
+
157
+ protected
158
+ def stylesheet_header
159
+ return @stylesheet_header unless @stylesheet_header.nil?
160
+
161
+ file = @task.find_in_source_paths(File.join('config', 'stylesheet_header.erb'))
162
+ @stylesheet_header = File.expand_path(file)
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,86 @@
1
+ require 'thor'
2
+ require 'yaml'
3
+ require 'guard/forge/assets'
4
+ require 'guard/forge/config'
5
+ require 'guard/forge/templates'
6
+ require 'guard/forge/functions'
7
+
8
+ module Forge
9
+ class CLI < Thor
10
+ include Thor::Actions
11
+
12
+ def self.source_root
13
+ File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'layouts'))
14
+ end
15
+
16
+ desc "create DIRECTORY", "Creates a Forge project"
17
+ method_option :name, :type => :string, :desc => "The theme name"
18
+ method_option :uri, :type => :string, :desc => "The theme's uri"
19
+ method_option :author, :type => :string, :desc => "The author of the theme"
20
+ method_option :author_uri, :type => :string, :desc => "The author's uri"
21
+ method_option :interactive, :type => :boolean, :desc => "Use interactive configuration setup", :aliases => "-i"
22
+ def create(dir)
23
+ prompts = {
24
+ :name => "What is the name of this theme?",
25
+ :uri => "What is the website for this theme?",
26
+ :author => "Who is the author of this theme?",
27
+ :author_uri => "What is the author's website?"
28
+ }
29
+
30
+ theme = {}
31
+
32
+ prompts.each do |k,v|
33
+ theme[k] = options[k]
34
+ theme[k] = ask(v) if options[:interactive]
35
+ end
36
+
37
+ theme[:name] = dir if (theme[:name].nil? || theme[:name].empty?)
38
+
39
+ project = Forge::Project.create(dir, theme, self)
40
+ end
41
+
42
+ desc "link PATH", "symlink the compiled version of theme to the specified path"
43
+ long_desc "This command will symlink the compiled version of the theme to the specified path.\n\n"+
44
+ "To compile the theme use the `forge watch` command"
45
+ def link(path)
46
+ project = Forge::Project.new('.', self)
47
+
48
+ FileUtils.mkdir_p project.build_path unless File.directory?(project.build_path)
49
+
50
+ do_link(project, path)
51
+ end
52
+
53
+ desc "watch", "Start watch process"
54
+ def watch
55
+ project = Forge::Project.new('.', self)
56
+
57
+ # Empty the build directory before starting up to clean out old files
58
+ FileUtils.rm_rf project.build_path
59
+ FileUtils.mkdir_p project.build_path
60
+
61
+ Forge::Guard.start(project, self)
62
+ end
63
+
64
+ desc "package", "Compile and zip your project"
65
+ def package
66
+ project = Forge::Project.new('.', self)
67
+
68
+ builder = Builder.new(project)
69
+ builder.build
70
+ builder.zip
71
+ end
72
+
73
+ protected
74
+ def do_link(project, path)
75
+ begin
76
+ project.link(path)
77
+ rescue LinkSourceDirNotFound
78
+ say_status :error, "The path #{File.dirname(path)} does not exist", :red
79
+ exit 2
80
+ rescue Errno::EEXIST
81
+ say_status :error, "The path #{path} already exsts", :red
82
+ exit 2
83
+ end
84
+ end
85
+ end
86
+ end