@@ -75,6 +75,7 @@ make_constructor.Geom <- function(x, ..., checks = exprs(), env = caller_env())
75
75
args [param ] <- draw_args [param ]
76
76
}
77
77
}
78
+ extra_args <- intersect(extra_args , names(args ))
78
79
missing_params <- setdiff(missing_params , names(args ))
79
80
if (length(missing_params ) > 0 ) {
80
81
cli :: cli_warn(
@@ -122,5 +123,90 @@ make_constructor.Geom <- function(x, ..., checks = exprs(), env = caller_env())
122
123
# We encapsulate rlang::list2
123
124
new_env <- new_environment(list (list2 = list2 ), env )
124
125
125
- new_function(fmls , body , env = new_env )
126
+ new_function(fmls , body , new_env )
126
127
}
128
+
129
+ # ' @export
130
+ # ' @rdname make_constructor
131
+ make_constructor.Stat <- function (x , ... , checks = exprs(), env = caller_env()) {
132
+ # Check that we can independently find the stat
133
+ stat <- gsub(" ^stat_" , " " , snake_class(x ))
134
+ check_subclass(stat , " Stat" , env = env )
135
+
136
+ # Split additional arguments into required and extra ones
137
+ args <- enexprs(... )
138
+ fixed_fmls_names <- c(" mapping" , " data" , " geom" , " position" , " ..." ,
139
+ " na.rm" , " show.legend" , " inherit.aes" )
140
+ extra_args <- setdiff(names(args ), fixed_fmls_names )
141
+ if (" stat" %in% extra_args ) {
142
+ cli :: cli_abort(" {.arg stat} is a reversed argument." )
143
+ }
144
+
145
+ known_params <-
146
+ unique(c(names(args ), fixed_fmls_names , " flipped_aes" , x $ aesthetics()))
147
+ missing_params <- setdiff(x $ parameters(), known_params )
148
+
149
+ # Fill in missing parameters from the compute methods
150
+ if (length(missing_params ) > 0 ) {
151
+ compute_args <- ggproto_formals(x $ compute_panel )
152
+ if (" ..." %in% names(compute_args )) {
153
+ compute_args <- ggproto_formals(x $ compute_group )
154
+ }
155
+ params <- intersect(missing_params , names(compute_args ))
156
+ extra_args <- c(extra_args , params )
157
+ for (param in params ) {
158
+ if (! identical(compute_args [[param ]], missing_arg())) {
159
+ args [param ] <- compute_args [param ]
160
+ }
161
+ }
162
+ extra_args <- intersect(extra_args , names(args ))
163
+ missing_params <- setdiff(missing_params , names(args ))
164
+ if (length(missing_params ) > 0 ) {
165
+ cli :: cli_warn(
166
+ " In {.fn stat_{stat}}: please consider providing default values for: \\
167
+ {missing_params}."
168
+ )
169
+ }
170
+ }
171
+
172
+ # Build function formals
173
+ fmls <- pairlist2(
174
+ mapping = args $ mapping ,
175
+ data = args $ data ,
176
+ geom = args $ geom %|| % cli :: cli_abort(" {.arg geom} is required." ),
177
+ position = args $ position %|| % " identity" ,
178
+ `...` = missing_arg(),
179
+ !!! args [extra_args ],
180
+ na.rm = args $ na.rm %|| % FALSE ,
181
+ show.legend = args $ show.legend %|| % NA ,
182
+ inherit.aes = args $ inherit.aes %|| % TRUE
183
+ )
184
+
185
+ # Construct params for the `layer(params)` argument
186
+ params <- exprs(!!! syms(c(" na.rm" , extra_args )), .named = TRUE )
187
+ params <- call2(" list2" , !!! params , quote(... ))
188
+
189
+ # Construct rest of `layer()` call
190
+ layer_args <- syms(setdiff(fixed_fmls_names , c(" ..." , " na.rm" )))
191
+ layer_args <- append(layer_args , list (stat = stat ), after = 3 )
192
+ layer_args <- exprs(!!! layer_args , params = !! params , .named = TRUE )
193
+ body <- call2(" layer" , !!! layer_args )
194
+
195
+ # Prepend any checks
196
+ if (length(exprs ) > 0 ) {
197
+ lang <- vapply(checks , is_call , logical (1 ))
198
+ if (! all(lang )) {
199
+ cli :: cli_abort(
200
+ " {.arg checks} must be a list of calls, such as one constructed \\
201
+ with {.fn rlang::exprs}."
202
+ )
203
+ }
204
+ }
205
+ body <- call2(" {" , !!! checks , body )
206
+
207
+ # We encapsulate rlang::list2
208
+ new_env <- new_environment(list (list2 = list2 ), env )
209
+
210
+ new_function(fmls , body , new_env )
211
+ }
212
+
0 commit comments